Acerca de esta regla de accesibilidad
Las tablas de datos comunican información estructurada donde el significado de cada celda depende de su posición relativa a los encabezados de fila y columna. Cuando miras una tabla visualmente, tus ojos naturalmente se dirigen hacia los encabezados para entender qué representa un valor particular. Los lectores de pantalla replican este comportamiento anunciando los encabezados relevantes mientras los usuarios navegan entre celdas — pero solo cuando los encabezados están correctamente marcados en el HTML.
Sin las asociaciones adecuadas de encabezados, un lector de pantalla podría anunciar un valor de celda como “28:04” sin contexto. El usuario no tendría manera de saber qué representa ese número, a quién pertenece, o en qué categoría se encuentra. Esta es una barrera crítica de accesibilidad para personas ciegas o sordociegas.
Esta regla se relaciona con el Criterio de Éxito 1.3.1 de WCAG 2.1 (Información y Relaciones), que requiere que la información y las relaciones transmitidas a través de la presentación visual sean determinables programáticamente. También es requerido por las directrices de la Sección 508, que exigen que se identifiquen los encabezados de fila y columna para las tablas de datos y que se use marcado para asociar las celdas de datos con las celdas de encabezado para tablas con dos o más niveles lógicos de encabezados.
La regla de axe td-has-header verifica tablas que tienen al menos 3 celdas de ancho y 3 celdas de alto. Si algún <td> no vacío en dicha tabla carece de un encabezado asociado, la regla falla.
Cómo solucionarlo
Hay dos técnicas principales para asociar celdas de datos con encabezados:
Usar <th> con scope
Este es el enfoque más simple y preferido para tablas directas. Reemplaza los elementos <td> de las celdas de encabezado con elementos <th> y añade un atributo scope:
-
Usa
scope="col"para encabezados de columna. -
Usa
scope="row"para encabezados de fila.
Los lectores de pantalla usan el atributo scope para determinar qué celdas de datos pertenecen a qué encabezado. Este enfoque funciona bien para tablas donde cada columna y fila tiene un solo encabezado.
Usar id y headers
Para tablas complejas — como aquellas con celdas combinadas, múltiples niveles de encabezados, o estructuras irregulares — usa el método id y headers. Dale a cada <th> un id único, luego añade un atributo headers a cada <td> listando los valores id de todos los encabezados que aplican a esa celda, separados por espacios.
Este método es más verboso pero te permite definir explícitamente exactamente qué encabezados se relacionan con cada celda de datos, independientemente de la complejidad de la tabla. Cuando sea posible, considera dividir una tabla compleja en múltiples tablas más simples, lo cual beneficia a todos los usuarios.
Ejemplos
Falla: tabla sin encabezados
Esta tabla no tiene elementos <th> en absoluto, por lo que los lectores de pantalla no pueden asociar ninguna celda de datos con un encabezado.
<table>
<tr>
<td>Name</td>
<td>1 mile</td>
<td>5 km</td>
<td>10 km</td>
</tr>
<tr>
<td>Mary</td>
<td>8:32</td>
<td>28:04</td>
<td>1:01:16</td>
</tr>
<tr>
<td>Betsy</td>
<td>7:43</td>
<td>26:47</td>
<td>55:38</td>
</tr>
</table>
Pasa: tabla simple con scope
Los encabezados de columna usan scope="col" y los encabezados de fila usan scope="row", dando a cada <td> una asociación clara.
<table>
<caption>Greensprings Running Club Personal Bests</caption>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">1 mile</th>
<th scope="col">5 km</th>
<th scope="col">10 km</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Mary</th>
<td>8:32</td>
<td>28:04</td>
<td>1:01:16</td>
</tr>
<tr>
<th scope="row">Betsy</th>
<td>7:43</td>
<td>26:47</td>
<td>55:38</td>
</tr>
<tr>
<th scope="row">Matt</th>
<td>7:55</td>
<td>27:29</td>
<td>57:04</td>
</tr>
</tbody>
</table>
Cuando un usuario de lector de pantalla navega a la celda que contiene “26:47”, el lector de pantalla anuncia algo como “Betsy, 5 km, 26:47” — proporcionando contexto completo.
Pasa: tabla compleja con id y headers
Cuando una tabla tiene múltiples niveles de encabezados o celdas combinadas, el método id y headers te da control explícito sobre las asociaciones.
<table>
<caption>Race Results by Category</caption>
<thead>
<tr>
<td></td>
<th id="road" colspan="2">Road Races</th>
<th id="track" colspan="2">Track Events</th>
</tr>
<tr>
<td></td>
<th id="r5k">5 km</th>
<th id="r10k">10 km</th>
<th id="t800">800 m</th>
<th id="t1500">1500 m</th>
</tr>
</thead>
<tbody>
<tr>
<th id="mary">Mary</th>
<td headers="mary road r5k">28:04</td>
<td headers="mary road r10k">1:01:16</td>
<td headers="mary track t800">2:34</td>
<td headers="mary track t1500">5:51</td>
</tr>
<tr>
<th id="betsy">Betsy</th>
<td headers="betsy road r5k">26:47</td>
<td headers="betsy road r10k">55:38</td>
<td headers="betsy track t800">2:17</td>
<td headers="betsy track t1500">5:09</td>
</tr>
</tbody>
</table>
En este ejemplo, cuando un lector de pantalla llega a “26:47”, puede anunciar “Betsy, Road Races, 5 km, 26:47” porque el atributo headers lista explícitamente los tres valores id de encabezado relevantes.
Puntos clave a recordar
-
Usa siempre
<th>para celdas de encabezado, no elementos<td>con estilo. -
Añade un
<caption>para dar a tu tabla un nombre descriptivo. -
Usa
scopepara tablas simples eid+headerspara las complejas. -
Las celdas
<td>vacías están excluidas de esta regla — solo las celdas de datos no vacías necesitan asociaciones de encabezado. - El estilo visual (bordes, fuentes, fondos) debe manejarse con CSS y no tiene impacto en el marcado de accesibilidad.
Learn more:
Ayúdanos a mejorar nuestras guías
Detecta problemas de accesibilidad automáticamente
Rocket Validator escanea miles de páginas con Axe Core y el W3C Validator, encontrando problemas de accesibilidad en todo tu sitio web.