Für www.berlinonline.net müssen neben Text und Grafiken auch tabellarische Daten dargestellt werden, z.B. Preislisten. Auf ausreichend großen Displays ist die Darstellung einer Tabelle meist unproblematisch, sofern sie nicht zu viele und zu breite Spalten beinhaltet.

Screenshot: Tabelle im Desktoplayout

Sollen die gleichen Daten jedoch auf kleineren Displays wie Tablets oder Smartphones dargestellt werden, muss entweder horizontal gescrollt oder die Tabelle umformatiert werden. Aus Sicht der Usability ist horizontales Scrollen auf einer ansonsten vertikal aufgebauten Seite zu vermeiden.

Um die Daten trotzdem darstellen zu können, können wir uns verscheidener Möglichkeiten bedienen. Spalten auszublenden ist zwar die einfachste Lösung, eignet sich hier jedoch nicht, da keine Spalte wirklich verzichtbar ist. Wir verfolgen den Ansatz, die Zeilen den Tabelle als Listenblöcke darzustellen.

Screenshot: Tabelle im Mobillayout

Dabei wird jede Zelle zu einem Listeneintrag und jede Zeile ein Block. Die Zeilenbeschriftung wird zur Zwischenüberschrift.

Die Methode, mit der wir die Tabelle umformatieren können wir an einem einfacheren Beispiel demonstrieren:

HTML

    <table>
        <thead>
            <tr>
                <td></td>
                <th scope="col">A<sup><a href="#a">a</a></sup></th>
                <th scope="col">B<sup><a href="#b">b</a></sup></th>
                <th scope="col">C<sup><a href="#c">c</a></sup></th>
                <th scope="col">D<sup><a href="#d">d</a></sup></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th scope="row">1</th>
                <td data-title="A">A1</td>
                <td data-title="B">B1</td>
                <td data-title="C">C1</td>
                <td data-title="D">D1</td>
            </tr>
            <tr>
                <th scope="row">2</th>
                <td data-title="A">A2</td>
                <td data-title="B">B2</td>
                <td data-title="C">C2</td>
                <td data-title="D">D2</td>
            </tr>
            <tr>
                <th scope="row">3</th>
                <td data-title="A">A3</td>
                <td data-title="B">B3</td>
                <td data-title="C">C3</td>
                <td data-title="D">D3</td>
            </tr>
        </tbody>
    </table>

SCSS

    table {
        width: 100%;
        border-collapse: collapse;
    }

<span class="nt">thead</span> <span class="p">{</span>

    <span class="nt">th</span><span class="o">,</span> <span class="nt">td</span> <span class="p">{</span>
        <span class="nl">border-bottom</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="no">black</span><span class="p">;</span>
        <span class="nl">text-align</span><span class="p">:</span> <span class="nb">right</span><span class="p">;</span>
        <span class="nl">color</span><span class="p">:</span> <span class="no">red</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nt">tbody</span> <span class="p">{</span>
    <span class="nt">td</span> <span class="p">{</span>
        <span class="nl">text-align</span><span class="p">:</span> <span class="nb">right</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nt">th</span> <span class="p">{</span>
        <span class="nl">color</span><span class="p">:</span> <span class="mh">#0d0</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">@media</span> <span class="p">(</span><span class="n">max-width</span><span class="o">:</span> <span class="m">400px</span><span class="p">)</span> <span class="p">{</span>
    <span class="nt">table</span><span class="o">,</span>
    <span class="nt">thead</span><span class="o">,</span>
    <span class="nt">tbody</span><span class="o">,</span>
    <span class="nt">tfoot</span><span class="o">,</span>
    <span class="nt">tr</span><span class="o">,</span>
    <span class="nt">th</span><span class="o">,</span>
    <span class="nt">td</span> <span class="p">{</span>
        <span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nt">table</span> <span class="p">{</span>
        <span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nt">thead</span> <span class="p">{</span>
        <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
        <span class="nl">top</span><span class="p">:</span> <span class="m">38px</span><span class="p">;</span>
        <span class="nl">left</span><span class="p">:</span> <span class="m">1em</span><span class="p">;</span>
        <span class="nt">td</span> <span class="p">{</span>
            <span class="nl">display</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="nt">th</span> <span class="p">{</span>
            <span class="nl">border</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
        <span class="nl">height</span><span class="p">:</span> <span class="m">19px</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="nt">tbody</span> <span class="p">{</span>
        <span class="nt">th</span> <span class="p">{</span>
            <span class="nl">text-align</span><span class="p">:</span> <span class="nb">right</span><span class="p">;</span>
            <span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.2em</span><span class="p">;</span>
            <span class="nl">margin</span><span class="p">:</span> <span class="m">1em</span> <span class="m">1em</span><span class="p">;</span>
            <span class="nl">border-bottom</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="no">black</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="nt">td</span> <span class="p">{</span>
            <span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span>
            <span class="nl">margin-right</span><span class="p">:</span> <span class="m">1em</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="na">td</span><span class="p">:</span><span class="o">:</span><span class="n">before</span> <span class="p">{</span>
            <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
            <span class="nl">top</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
            <span class="nl">left</span><span class="p">:</span> <span class="m">1em</span><span class="p">;</span>
            <span class="nl">content</span><span class="p">:</span> <span class="nf">attr</span><span class="p">(</span><span class="n">data-title</span><span class="p">);</span>
            <span class="nl">color</span><span class="p">:</span> <span class="no">red</span><span class="p">;</span>
            <span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="nt">tr</span><span class="nd">:first-child</span> <span class="nt">td</span><span class="nd">:before</span> <span class="p">{</span>
            <span class="nl">display</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="na">td</span><span class="p">:</span><span class="o">:</span><span class="n">after</span> <span class="p">{</span>
            <span class="nl">content</span><span class="p">:</span> <span class="s2">"................................"</span><span class="p">;</span>
            <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
            <span class="nl">bottom</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
            <span class="nl">left</span><span class="p">:</span> <span class="m">3em</span><span class="p">;</span>
            <span class="nl">right</span><span class="p">:</span> <span class="m">3em</span><span class="p">;</span>
            <span class="nl">overflow</span><span class="p">:</span> <span class="nb">hidden</span><span class="p">;</span>
            <span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">1em</span><span class="p">;</span>
            <span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="mi">.3</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

Der komplette Beispielcode ist auch auf JsFiddle zu finden.

Die Styles außerhalb des Media-Queries dienen lediglich der farblichen Kennzeichnung und übersichtlicheren Formatierung der Tabelle in beiden Darstellungsformen. Innerhalb des Media-Queries werden zunächst alle Tabellen Elemente (table, thead, tbody, tfoot, tr, td) auf display:block umgestellt, damit sie sich wie normale Blockelemente wie <div> verhalten. Das allein bewirkt, dass nun alle Element untereinander aufgereiht sind.

Um die Zeilenbeschriftung an jeder einzelnen Zelle anzuzeigen bekommen die <td>-Elemente nun jeweils ein :before-Pseudoelement, dessen Textinhalt sich aus dem data-title-Attribut der Zelle befüllt. Die Pseudoelemente werden innerhalb der Zelle absolut positioniert, so dass sie am linken Rand stehen. Nun hat jede Zelle wieder ihre passende Beschriftung. Die data-Attribute haben ansonsten keine Auswirkungen, stören also auch nicht die Zugänglichkeit der Tabelle in Textbrowsern oder Screenreadern.

Um an den Zellenbeschriftungen im obersten Listenblock nun noch die Annotationen anzuzeigen, werden die :before-Pseudoelemente im obersten Block ausgeblendet und stattdessen die "echten" Spaltentitelzellen an deren Position verschoben. Somit sind die Inhalte und Links der Annotationen weiterhin erreichbar.

Für bessere Lesbarkeit der Listenansicht wird pro Zelle ein zusätzliches :after-Pseudoelement erzeugt, welches mit Punkten gefüllt und sich über die Breite der Zelle erstreckt, mit festen Abständen links und rechts.

Einen möglichen Anwendungsfall für die Annotationen beschreiben wir in einem späteren Artikel. Auf berlinonline.net verwenden wir sie, um Fußnoten an Tabellen als Dialoge anzuzeigen und sie trotzdem zugänglich für Textbrowser und Screenreader zu machen.