Tabellen
Zuletzt geprüft am von Daniel Weihmann

Tabellen sind für Daten da, nicht für Layout. Das ist die eine Regel, die seit zwanzig Jahren gilt und trotzdem wiederholt werden muss. Alles, was mit Anordnung zu tun hat, macht heute CSS Grid oder Flexbox. Was in eine Tabelle gehört, erkennt man daran, dass jede Zelle über zwei Angaben bestimmt ist: ihre Zeile und ihre Spalte.
Der Grund ist nicht Rechthaberei, sondern die Ausgabe: Ein Screenreader liest eine Tabelle anders vor als Fließtext. Er kündigt Größe und Kopfzeilen an und nennt bei jeder Zelle, zu welcher Spalte und Zeile sie gehört. Steckt darin ein Seitenlayout, ist das Ergebnis unbrauchbar.
Der Aufbau
<table>
<caption>Öffnungszeiten der Filialen</caption>
<thead>
<tr>
<th scope="col">Filiale</th>
<th scope="col">Werktags</th>
<th scope="col">Samstag</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Köthen</th>
<td>9 bis 18 Uhr</td>
<td>9 bis 13 Uhr</td>
</tr>
</tbody>
</table>
- <caption>
-
Der Name der Tabelle. Muss als erstes Kind direkt nach
<table>stehen. Screenreader lesen ihn vor der Tabelle vor, damit klar ist, was da gleich kommt. Soll er nicht sichtbar sein, gehört er trotzdem ins Markup und wird per CSS ausgeblendet – aber mit einer Technik, die ihn für Hilfsmittel erhält, nicht mitdisplay: none. - <thead>, <tbody>, <tfoot>
-
Gliedern die Tabelle in Kopf, Rumpf und Fuß. Beim Drucken langer Tabellen
wiederholen Browser den
<thead>auf jeder Seite. Ein<tfoot>nimmt Summenzeilen auf und darf im Quelltext heute an seiner logischen Stelle am Ende stehen. - <th> gegen <td>
-
<th>ist eine Kopfzelle,<td>eine Datenzelle. Kopfzellen stehen nicht nur oben: Die erste Spalte einer Zeile ist oft ebenfalls eine, siehe „Köthen" im Beispiel. - scope
-
Sagt, wofür eine Kopfzelle zuständig ist –
colfür die Spalte darunter,rowfür die Zeile daneben. Das ist die wichtigste einzelne Angabe in einer Tabelle: Ohne sie muss der Screenreader raten, und aus „Köthen, 9 bis 18 Uhr" wird eine Zahlenkette ohne Bezug.
Zellen verbinden
colspan zieht eine Zelle über mehrere Spalten,
rowspan über mehrere Zeilen. Beide erwarten eine Anzahl, nicht
eine Zielposition:
<tr>
<th scope="row" rowspan="2">Köthen</th>
<td>Vormittag</td>
</tr>
<tr>
<td>Nachmittag</td>
</tr>
In der zweiten Zeile fehlt die erste Zelle bewusst, sie ist von oben belegt. Verrechnet man sich dabei, verschiebt sich der Rest der Tabelle – ein Fehler, den der Validator zuverlässig meldet.
Bei Tabellen mit zwei Kopfebenen reicht scope nicht mehr. Dann
bekommen die Kopfzellen eine id, und die Datenzellen verweisen mit
headers darauf. Das ist aufwendig – und meistens ein Hinweis
darauf, dass zwei einfache Tabellen die bessere Lösung wären.
Tabellen auf schmalen Bildschirmen
Eine Tabelle lässt sich nicht sinnvoll umbrechen: Ihre Spalten hängen zusammen. Der Weg, der am wenigsten kaputtmacht, ist deshalb, sie in einem eigenen Bereich waagerecht scrollen zu lassen, statt die ganze Seite zu sprengen.
<div class="table-scroll" tabindex="0" role="region"
aria-label="Öffnungszeiten">
<table> … </table>
</div>
Das tabindex="0" ist kein Schmuck: Ohne es lässt sich ein
scrollbarer Bereich nicht mit der Tastatur erreichen, wer also keine Maus
benutzt, kommt an die rechten Spalten nicht heran. Zusammen mit
role="region" und einem Namen wird daraus ein Bereich, den
Screenreader ansteuern können.
Achtung bei Grid und Flexbox: Steht eine Tabelle in einer
Grid-Spalte mit 1fr, zieht sie die Spalte auf ihre eigene
Mindestbreite auf und sprengt das Layout trotz
overflow-x: auto. Die Spalte braucht dann
minmax(0, 1fr), damit der Scroll-Container greifen kann.
Darstellung
Zwei Kleinigkeiten machen Tabellen deutlich lesbarer. Zum einen
border-collapse: collapse, damit aus doppelten Rahmen einfache
Linien werden. Zum anderen die Ausrichtung: Text steht links, Zahlen rechts,
und zwar Kopf- wie Datenzelle. So stehen Einer unter Einern und Zehner unter
Zehnern, was den Vergleich überhaupt erst möglich macht. Wer mit
font-variant-numeric: tabular-nums arbeitet, bekommt zusätzlich
gleich breite Ziffern.
Für die Breite einzelner Spalten gibt es <colgroup> und
<col>. Damit lässt sich eine Spalte gezielt ansprechen,
ohne jeder Zelle eine Klasse zu geben – nützlich, wenn die Tabelle aus einer
Datenquelle erzeugt wird.
Häufige Fehler
-
Kopfzeile aus
<td>mit fetter Schrift. Sieht gleich aus, ist aber keine Kopfzeile. Für Hilfsmittel existiert der Bezug dann nicht. -
scopevergessen. Der häufigste Befund in Prüfberichten zu Tabellen. -
Leere Zellen für Abstand. Werden mitvorgelesen. Abstand
macht
padding. - Verschachtelte Tabellen. Erlaubt, aber beim Vorlesen kaum zu durchdringen. Fast immer lässt sich das auflösen.
-
Feste Pixelbreiten. Eine Tabelle mit
width="900"passt auf kein Telefon. Prozentwerte oder gar keine Angabe plus Scroll-Container sind der bessere Weg. -
Die Tabelle ist eigentlich eine Liste. Eine einspaltige
Tabelle ist ein
<ul>. Zwei Spalten aus Begriff und Erklärung sind eine Definitionsliste.
