Ir directamente al contenido de esta página
La introducción a la pauta 5 de las WCAG 1.0 (Create tables that transform gracefully) (inglés), comienza con la siguiente afirmación:
Tables should be used to mark up truly tabular information («data tables»). Content developers should avoid using them to lay out pages («layout tables»).
[Las tablas deben emplearse para marcar auténtica información tabular («tablas de datos»). Los desarrolladores de contenidos deberían evitar emplearlas para maquetar páginas («tablas de presentación»).]
Hay dos cosas sobre las que nunca discuto: una, que Deborah Kara Unger (inglés) es la mujer más hermosa del mundo; dos, que las tablas no se deben emplear para maquetar. Pero esto no quiere decir que deban ser desterradas de las páginas web, sino que, como todos los elementos, deben emplearse para el fin para el que fueron creadas, es decir, presentar datos organizados sobre las relaciones que se establecen entre ellos.
Desde el punto de vista de la accesibilidad, las tablas de datos cuentan con una serie de exigencias debidas, principalmente, a que muchas de las discapacidades en relación con la red son visuales.
Los usuarios ciegos acceden a las páginas a través de lectores de pantalla —un tipo de aplicación que sintetiza una voz que va leyendo el documento— o a través de una interfaz braille —una consola con cilindros móviles que sobresalen o se ocultan para formar el alfabeto, en dirección derecha-izquierda como un teletipo—. En ambos casos, lo que el usuario obtiene es una lectura lineal de los contenidos: las celdas se leen en el orden de lectura del idioma del documento —izquierda-derecha o derecha-izquierda—, y de arriba abajo. Es decir, el usuario escucharía las celdas de la primera fila, después las de la segunda, después la de la tercera y así sucesivamente.
La principal desventaja de esta lectura es que, por lo general, los encabezados de las celdas que dan sentido a los contenidos suelen aparecer al comienzo de la tabla. El usuario de un lector ha podido escuchar los encabezados al comienzo de la lectura, pero es muy probable que unas pocas filas más abajo no recuerde qué encabezado correspondía a qué celda.
La solución está en vincular explícitamente cada celda con sus correspondiente encabezado, para que, en caso de necesidad, el usuario pueda escuchar o leer en braille los datos asociados.
Desde el punto de vista técnico, se trata de emplear los elementos y atributos apropiados para añadir contenido semántico a las tablas. Pero mejor que dar una lista, vamos a trabajar sobre unos cuantos ejemplos.
Primero, veamos lo que dicen las Pautas del W3C sobre el particular, en su punto 5.1 (inglés), de prioridad 1:
For data tables, identify row and column headers.
[Para tablas de datos, identifique los encabezados de fila y columna.]
Ahora, vamos a echar un ojo a una tabla generada con Dreamweaver 8:
<table width="100%" border="0" cellspacing="0">
<tr>
<td colspan="2" class="Estilo2"><div align="center"><strong>Velocidad orbital media [kms/s]: Tierra y Venus</strong></div></td>
</tr>
<tr>
<td class="Estilo3"><div align="center">Tierra</div></td>
<td class="Estilo3"><div align="center">Venus</div></td>
</tr>
<tr>
<td class="Estilo4">30,287</td>
<td class="Estilo4">35,021</td>
</tr>
</table>
Los editores de código visuales son especialmente útiles a la hora de crear tablas, sobre todo cuando son complejas —veremos luego un caso duro de codificar «a mano»—, pero hay que mantener el código que generan bajo control.
Aunque el código de la tabla es casi válido —sólo presenta un error de validación de salida—, carece de elementos semánticos para los contenidos importantes.
Antes de continuar, me gustaría señalar un error común con respecto a las tablas, y el código de una página en general, y es que muchos desarrolladores que se «actualizan» a CSS creen que basta con presentar la tabla eliminando los atributos de presentación para que esta sea accesible. Craso error.
La misma tabla anterior, depurada y válida, podría ser así:
<table>
<tr>
<td class="titulo" colspan="2">Velocidad orbital media [<abbr title="kilómetros por segundo">kms/s</abbr>]: Tierra y Venus</td>
</tr>
<tr>
<td class="planeta">Tierra</td>
<td class="planeta">Venus</td>
</tr>
<tr>
<td>30,287</td>
<td>35,021</td>
</tr>
</table>
Como se puede comprobar, la tabla ahora es válida, pero no hemos mejorado su accesibilidad lo más mínimo. Para ello, deberíamos marcarla de manera similar a ésta:
<table summary="Comparativa de velocidades orbitales medias: la Tierra y Venus.">
<caption>Velocidad orbital media [<abbr title="kilómetros por segundo">kms/s</abbr>]: Tierra y Venus</caption>
<thead>
<tr>
<th>Tierra</th>
<th>Venus</th>
</tr>
</thead>
<tbody>
<tr>
<td>30,287</td>
<td>35,021</td>
</tr>
</tbody>
</table>
Lo que he hecho ha sido añadir contenido semántico:
summary
al elemento table
, que sirve para ofrecer a los usuarios de un lector de pantalla un resumen del contenido de la tabla, que les permita decidir si seguir leyendo la tabla, u obviarla. Aunque el punto donde se indica que se debe incluir este atributo —el 5.5 (inglés)— es de prioridad 3, no parece que aplicarlo suponga un esfuerzo ímprobo. Como en tantos otros casos, hacer el bien no cuesta nada.caption
, que es el elemento específico para indicar precisamente eso, el título. caption
no es obligatorio, pero de aparecer debe aparecer inmediatamente después de la etiqueta de apertura de table
, antes que cualquier otro elemento.thead
—, que contiene los encabezados, y su cuerpo —tbody
—, que contiene las celdas de datos. En este caso no sería necesario por la simplicidad de la tabla, pero, además de marcar más correctamente su estructura, puede ser útil para tener anclas adicionales para estilos sin necesidad de añadir clases. Ambos elementos son opcionales, pero en caso de emplearse uno se debe marcar el otro, y deben aparecer en el orden indicado.th
.Gracias a esto, el lector de pantalla no leerá «Velocidad orbital media [kms/s]: Tierra y Venus. Tierra Venus 30,287 35,021», sino «Velocidad orbital media [kms/s]: Tierra y Venus. Tierra 30,287 Venus 35,021». No parece una diferencia dramática, pero cuando se trara de diez filas y cinco columnas, puede ser la única manera de comprender su contenido.
Como veíamos arriba en la pauta, se deben especificar los encabezados tanto de las filas como de las columnas. Esto se aplica a tablas de dos niveles de th
. Al igual que antes, podemos tener una versión válida, y una además accesible:
<table summary="Comparativa de datos: la Tierra y Venus.">
<caption>Comparativa: Tierra y Venus</caption>
<thead>
<tr>
<td></td>
<th scope="col">Velocidad orbital media [<abbr title="kilómetros por segundo">kms/s</abbr>]</th>
<th scope="col">Inclinación [<abbr title="grados">°</abbr>]</th>
<th scope="col">Número de satélites</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Tierra</th>
<td>30,287</td>
<td>23,45</td>
<td>1</td>
</tr>
<tr>
<th scope="row">Venus</th>
<td>35,021</td>
<td>2,64</td>
<td>0</td>
</tr>
</tbody>
</table>
El proceso de hacer la tabla accesible es el mismo que antes, pero con un par de detalles añadidos:
thead
, los encabezados que aparece en las filas se deben marcar también como th
.scope="col"
para los encabezados de columnas, y scope="row"
para los encabezados de filas.Nuestra tabla de dos niveles ya está lista.
En general, sería bueno dividir las tablas más complejas en una serie de tablas simples, pero hay casos en los que no es posible. Así, podemos encontrarnos con tablas con encabezados y subencabezados, como la de este ejemplo.
Con respecto a estas tablas, lo que el punto 5.2 de las WCAG 1.0 nos dice es:
For data tables that have two or more logical levels of row or column headers, use markup to associate data cells and header cells. [Priority 1]
For example, in HTML, use THEAD, TFOOT, and TBODY to group rows, COL and COLGROUP to group columns, and the "axis", "scope", and "headers" attributes, to describe more complex relationships among data.
[Para tablas de datos que tengan dos o más niveles lógicos de encabezados de fila o columna, emplee el marcado para asociar las celdas de datos y las celdas de encabezados. (Prioridad 1)
Por ejemplo, en HTML, emplee
thead
,tfoot
ytbody
para agrupar filas,col
ycolgroup
para agrupar columnas, y los atributosaxis
,scope
yheaders
para describir las relaciones complejas entre datos.]
Bien, con estas indicaciones, podemos hacer accesible la tabla del ejemplo inmediatamente anterior:
<table summary="Comparativa de datos: la Tierra y Venus.">
<caption>Comparativa: Tierra y Venus</caption>
<colgroup></colgroup>
<colgroup><col /><col /></colgroup>
<colgroup><col /><col /></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<thead>
<tr>
<td rowspan="2"></td>
<th colspan="2" id="th_distancia">Distancia media al Sol</th>
<th colspan="2" id="th_periodo">Periodo orbital [días]</th>
<th rowspan="2" scope="col">Velocidad orbital media [<abbr title="kilómetros por segundo">kms/s</abbr>]</th>
<th rowspan="2" scope="col">Inclinación [<abbr title="grados">°</abbr>]</th>
<th rowspan="2" scope="col">Número de satélites</th>
</tr>
<tr>
<th abbr="unidades astronómicas" id="th_ua">UA</th>
<th abbr="kilómetros" id="th_kms">Kms</th>
<th id="th_sideral">Sideral</th>
<th id="th_sinodico">Sinódico</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" id="th_tierra">Tierra</th>
<td headers="th_tierra th_distancia th_ua">1</td>
<td headers="th_tierra th_distancia th_kms">149.675.000</td>
<td headers="th_tierra th_periodo th_sideral">365,256</td>
<td headers="th_tierra th_periodo th_sinodico"><abbr title="no aplicable">n/a</abbr></td>
<td>30,287</td>
<td>23,45</td>
<td>1</td>
</tr>
<tr>
<th scope="row" id="th_venus">Venus</th>
<td headers="th_venus th_distancia th_ua">0,72333199</td>
<td headers="th_venus th_distancia th_kms">108.208.930</td>
<td headers="th_venus th_periodo th_sideral">224,701</td>
<td headers="th_venus th_periodo th_sinodico">583,92</td>
<td>35,021</td>
<td>2,64</td>
<td>0</td>
</tr>
</tbody>
</table>
Como se ve, la complejidad del código aumenta proporcionalmente a la complejidad de la tabla:
Primero, indico la estructura de columnas:
col
anidado.<colgroup><col /><col /></colgroup>
.El marcado es poco intuitivo al principio, puesto que marcamos una estructura que, a diferencia del resto de elementos, no engloba nunca contenido. Pero todo es acostumbrarse. Sólo hay que recordar que los grupos de columnas se deben indicar después de caption
e inmediatamente antes del resto de contenido de la tabla.
Después, como en el ejemplo de la sección anterior, empleamos scope
para indicar los encabezados de columna y los de fila. Sin embargo, esto no es suficiente para especificar las relaciones de las columnas con subencabezados con sus respectivos datos, ni para clarificar el orden de lectura para las tecnologías asistivas. Para eso se necesitan aún dos pasos:
id
los encabezados pertinentes de las columnas —«Distancia», «Periodo» y sus respectivos subencabezados— y de las filas —«Tierra» y «Venus»—headers
el orden de lectura de los encabezados, que recoge en su valor las lista de los id
de los encabezados oportunos, en el orden en que deben leerse y separados por espacios.Así, por ejemplo, las celdas con los valores 0,72333199
y 108.208.930
se leerían, respectivamente, «Venus Distancia media al Sol unidades astronómicas 0,72333199» y «Venus Distancia media al Sol kilómetros 108.208.930».
Por último, sólo quiero indicar unos detalles:
abbr
se emplea para la abreviatura de un encabezado de tabla extenso, para ahorrar tiempo de lectura y paciencia del oyente. Sin embargo, yo lo he empleado aquí para indicar la expansión de los encabezados de las unidades de distancias, porque me parece más significativo al escucharlo.axis
, puesto que su definición según se recogió en la última especificación de HTML (inglés) me resulta como la idea de Dios: confusa, profusa, difusa y obtusa.tfoot
, pero su uso es como el de thead
y el de tbody
. Las restricciones son que, al igual que estos, no puede aparecer si no se especifican los otros, y que debe situarse inmediatamente antes del elemento tbody
.Y, con esto, se cierra esta introducción a las tablas accesibles.