Waarom tabellen zo vaak fouten bevatten
Een tabel lijkt simpel: rijen, kolommen, klaar. Alleen: screenreaders lezen een tabel niet zoals jij ‘m ziet.
Gebruikers hebben context nodig bij elke cel: wat betekent deze waarde? Die context komt uit de juiste HTML-markup.
- Visueel klopt het, semantisch niet: headers worden “vetgedrukt” met CSS in plaats van echte
<th>-cellen. - Relaties ontbreken: bij grotere of complexere tabellen is niet duidelijk welke header bij welke data hoort.
- Complexiteit sluipt erin: samengevoegde cellen (
rowspan/colspan), meerdere headerlagen, lege hoekcellen… dat gaat snel mis. - Misbruik als layout: tabellen worden soms gebruikt om pagina’s “uit te lijnen” in plaats van data te tonen.
Wat gaat er het vaakst fout
- Geen
<th>gebruikt voor kopcellen (alleen<td>met styling). - Geen
scopebij headers in tabellen met één header-rij of -kolom (vooral als data “ambiguous” is). - Rij-headers vergeten (bijv. de eerste kolom is eigenlijk een header, maar staat als
<td>). - Onlogische structuur door samengevoegde cellen zonder duidelijke headerkoppeling.
- Geen caption of uitleg bij tabellen die zonder context lastig te begrijpen zijn.
- Informatie alleen via kleur/positie (bijv. “groen = open”) zonder tekst of duidelijke labels.
Wat is verplicht volgens WCAG 2.2
WCAG 2.2 vraagt (onder andere) dat informatie en relaties in content programmatisch bepaald kunnen worden, of in tekst beschikbaar zijn. Voor tabellen betekent dit: de relaties tussen headercellen en datacellen moeten in de HTML zitten, niet alleen in je vormgeving.
Minimale eisen voor toegankelijke datatabellen
- Gebruik echte tabelmarkup voor echte tabellen:
<table>, met<tr>voor rijen,<td>voor data en<th>voor headers. - Maak header-relaties expliciet:
- Bij eenvoudige tabellen: gebruik
scope="col"en/ofscope="row". - Bij complexere tabellen (meerdere headerlagen): gebruik
idop<th>enheadersop<td>waar nodig.
- Bij eenvoudige tabellen: gebruik
- Zorg voor een betekenisvolle structuur en volgorde: de leesvolgorde in de code moet logisch zijn (zoals de tabel bedoeld is).
- Geef context waar nodig: gebruik een
<caption>als “tabeltitel” en voeg een korte samenvatting toe bij complexere tabellen.
Vuistregel: als iemand de tabel met een screenreader per cel navigeert, moet steeds duidelijk zijn welke rij/kolom-header bij de huidige waarde hoort.
Codevoorbeelden
1) Tabel met 1 header-rij
Dit is een tabel met één header-rij. Door scope="col" te gebruiken is voor hulptechnologie duidelijk dat deze headers bij de kolommen horen.
WCAG 2.2 niveau AA criteria
| Niveau A | Niveau AA | Totaal |
|---|---|---|
| 9 | 12 | 21 |
| 14 | 5 | 19 |
| 7 | 6 | 2 |
| 1 | 1 | 2 |
In de broncode ziet deze tabel er als volgt uit:
<table>
<tbody>
<tr>
<th>Niveau A</th>
<th>Niveau AA</th>
<th>Totaal</th>
</tr>
<tr>
<td>9</td>
<td>12</td>
<td>21</td>
</tr>
<tr>
<td>14</td>
<td>5</td>
<td>19</td>
</tr>
<tr>
<td>7</td>
<td>6</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>2</td>
</tr>
</tbody>
</table>
2) Tabel met 2 headers (rij én kolom)
Hier heeft de tabel headers in de bovenste rij én in de eerste kolom. Met scope="col" en scope="row" leg je de relaties vast.
| Niveau A | Niveau AA | Totaal | |
|---|---|---|---|
| Waarneembaar | 9 | 12 | 21 |
| Bedienbaar | 14 | 5 | 19 |
| Begrijpelijk | 7 | 6 | 2 |
| Robuust | 1 | 1 | 2 |
In de broncode ziet dit er als volgt uit:
<table>
<caption>Verdeling van WCAG 2.2 succescriteria per principe en niveau</caption>
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Niveau A</th>
<th scope="col">Niveau AA</th>
<th scope="col">Totaal</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Waarneembaar</th>
<td>9</td>
<td>12</td>
<td>21</td>
</tr>
<tr>
<th scope="row">Bedienbaar</th>
<td>14</td>
<td>5</td>
<td>19</td>
</tr>
<tr>
<th scope="row">Begrijpelijk</th>
<td>7</td>
<td>6</td>
<td>2</td>
</tr>
<tr>
<th scope="row">Robuust</th>
<td>1</td>
<td>1</td>
<td>2</td>
</tr>
</tbody>
</table>