Tabellen/Responsive Gestaltung

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Unter einer responsiven Gestaltung einer Internetseite versteht man, dass das Layout der Seite für das Ausgabemedium angepasst wird. Übersetzt wird das englische Adjektiv „responsive“ etwa mit „ansprechbar“, „empfänglich“, „zugänglich“ oder „antwortend“, was auf den ersten Blick nicht sehr viel mit dem Internet zu tun hat. Worauf sollte eine Webseite ansprechen? Nun, eine Webseite kann das Medium, auf dem sie dargestellt wird, innerhalb gewisser Grenzen bereits rein mit CSS und vollumfänglich mit JavaScript analysieren. Sie „antwortet“ ihrem Ausgabemedium, indem sie eine dem Medium angepasste Darstellung zeigt.

Beachten Sie: Sie sollten die Darstellung nicht an eine bestimmte Viewportgröße koppeln, sondern tatsächlich nach Ihren Inhalten ausrichten.

Anhand einer Tabelle soll das Konzept beispielhaft vorgestellt werden. Das zugrundeliegende HTML ist dann auch einfach nur eine Tabelle. Um die Tabelle in verschiedenen Situationen zu sehen, können Sie die Größe des Browserfensters oder aber auch den Zoomfaktor verändern.

Tabelle ohne Spaltenüberschriften

Beispiel
<table>
  <thead>
    <tr>
      <th colspan="4">CSS im Wandel der Zeit</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th><code>font-size</code></th>
      <td><a href="…">wiki.selfhtml.org/wiki/font-size</a></td>
      <td>Die Eigenschaft <code>font-size</code> bestimmt die Darstellungsgröße der Schrift.</td>
      <td>
        <img src="css1.png" alt="Bestandteil von CSS 1">
        <img src="css2.png" alt="Bestandteil von CSS 2">
        <img src="css21.png" alt="Bestandteil von CSS 2.1">
        <img src="css3.png" alt="Bestandteil von CSS 3">
      </td>
    </tr></tbody>
</table>
allgemeines CSS ansehen …
table {
	border-collapse: collapse;
	border: thin solid;
	margin: 2em;
}

tr {
	border-top: thin solid;
	border-bottom: thin solid;
}

tr:first-child {
	border-top: 0 none;
}

th, td {
	padding: 1em;
}

thead tr, tr:nth-child(even) {
	background-color: lightgrey;
}

th {
	font-size: 1.2em;
}

tbody th {
	text-align: left;
}

code {
	font-size: 1.2em;
}

td:last-child {
	min-width: 180px;
	text-align: right;
}

img:not(:first-child) {
	margin-left: 5px;
}

Dieses CSS hat Einfluss auf die Gestaltung der Tabelle, die Tabelle wird jedoch unabhängig von den Abmessungen des Viewports dargestellt. Lediglich den Tabellenfeldern der letzten Spalte wurde eine Mindestbreite gegeben, damit die Grafiken hübsch nebeneinander bleiben.

Anpassung für breite Viewports

Wird das Browserfenster sehr breit, so wird in dieser Tabelle alles einzeilig, was ggf. unschön aussieht. Im Gegensatz dazu sind umbrochene Webadressen möglicherweise unerwünscht.

CSS für breite Viewports ansehen …
table {
	max-width: 80em;
}

td {
	text-align: justify;
}

table a {
	white-space: nowrap;
}

Mit diesem CSS wird dafür gesorgt, dass die Tabelle nicht breiter als 80em wird und Linktexte, im konkreten Fall Internetadressen, nicht umbrochen werden. Um den Feldern der 3. Spalte trotz fehlender vertikaler Rahmen auch visuell die gleiche Breite zu geben, wird der Text im Blocksatz ausgerichtet.

Anpassung für schmale Viewports

Wenn jetzt das Browserfenster schmaler gemacht wird, stellt man fest, dass unterhalb einer bestimmten Breite lediglich die dritte Spalte in der Breite verändert wird. Die erste wird nicht verändert, weil innerhalb von code-Elementen nur explizit gesetzte Zeilenumbrüche dargestellt werden, den Linktexten der zweiten Spalte haben wir den Umbruch verboten und die letzte Spalte hat eine Mindestbreite.

Die Tabelle wirkt dann äußerst unproportional.

Abhilfe schaffen gesonderte CSS-Anweisungen, falls die zur Verfügung stehende Breite des Anzeigebereichs unter einen bestimmten Wert fällt. In diesem Fall könnte dieser Wert 50em betragen; das ist Geschmackssache und hängt sehr von den anzuzeigenden Inhalten ab. Wir machen uns sogenannte Medienabfragen, media queries, zunutze.

CSS für schmale Viewports ansehen …
@media screen and (max-width: 60em) {
	table {
		width: 100%;
		margin: 0;
		border: none;
	}
	td {
		hyphens: auto;
	}
	table a {
		white-space: normal;
		hyphens: none;
	}
}

Dieses CSS wird nur angewendet, wenn das Ausgabemedium ein Bildschirm ist und die Breite des Anzeigebereichs 60em nicht überschreitet. Wir entfernen für die Tabelle Außenabstand und Rahmen und geben ihr die Breite des Viewports. Außerdem schalten wir für die dritte Spalte die automatische Silbentrennung ein und erlauben den Linkelementen, vor einem Schrägstrich umzubrechen.

Breitenänderungen wirken auch hier nur auf die Tabellenfelder der dritten Spalte. Wird der Bildschirm immer schmaler, haben wir wieder eine sehr unproportional wirkende Tabelle.

Container Queries für sehr schmale Viewports

Es ist an der Zeit, die Tabellenstruktur aufzulösen. Dafür nutzen wir anstelle einer Medienabfrage eine Container Query, die nur die Größe des Elternelements abfragt:

CSS für sehr schmale Viewports ansehen …
.table-container {
  container: card / inline-size;
  width: 35em;  /* Nur zum Testen: Verringern Sie den Wert auf <30em! */
}
@container (max-width: 30em) {
  table {
		display: block;
		border-collapse: collapse;
		width: 100%;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
  }

	tr, th, td {
		display: block;
	}
	
	tr {
		padding: 1em;
		border-top: 0 none;
	}
	
	th {
		padding: 0;
	}
	
	td {
		padding: 1em 0 0;
	}
}

Die Tabelle erhält nun ein wrapper-Element, dass mit container: card / inline-size; einen containment-context für dieses Eltern-Element erstellt.

Wir machen die Elemente der Tabelle allesamt zu Block-Elementen, während die Eigenschaft width: 100% sicherstellt, dass sie die volle Breite des enthaltenen Elements einnehmen. So werden sie vertikal gestapelt.

Die Eigenschaften overflow-x: auto und -webkit-overflow-scrolling: touch sorgen dafür, dass die Tabelle auf Touch-Geräten horizontal gescrollt werden kann. Dazu sortieren wir die Innenabstände ein wenig um und entfernen nun doppelte Rahmenlinien, weil border-collapse nur auf Elemente wirkt, deren display-Eigenschaft ein table im Namen hat.

Tabelle mit Spaltenüberschriften

Sehr häufig hat man Tabellen, bei denen die Kopfzeile die Überschriften der entsprechenden Spalten darstellt.

Beispiel
<table>
  <thead>
    <tr>
      <th>Rechnungsnummer</th>
      <th>Rechnungsdatum</th>
      <th>Rechnungshöhe</th>
      <th>Status</th>
      <th>Zahlungseingang</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th><a href="">201400132</a></th>
      <td>11.01.2014</td>
      <td>12,50 €</td>
      <td class="paid">bezahlt</td>
      <td>15.01.2014</td>
    </tr></tbody>
</table>

Im Kopf der Tabelle, also innerhalb von thead befinden sich die Überschriften der einzelnen Spalten. Das erste Feld einer jeden Zeile enthält die Rechnungsnummer, alle weiteren Datenfelder der Zeile beziehen sich auf genau diese Rechnung, deshalb sind sie ebenfalls als Überschrift-Elemente th ausgezeichnet.

allgemeines CSS ansehen …
table {
	border-collapse: collapse;
}
td, th {
	padding: 1em;
}
th:first-child {
	padding-left: .5em;
}
th:last-child, td:last-child {
	padding-right: .5em;
}
thead th {
	border-bottom: medium solid lightblue;
}
tbody th {
	font-weight: normal;
	text-align: left;
}
th a {
	background: url(pdf.png) no-repeat left center;
	padding: 15px 5px 15px 40px;
}
td {
	text-align: center;
}
td:nth-child(3) {
	text-align: right;
}
td:nth-child(4) {
	color: red;
	font-weight: bold;
}
td.paid {
	color: green;
	font-weight: normal;
}

Wie auch schon im ersten Beispiel nichts besonderes. Die Überschriftszellen lassen sich einzeln ansprechen, etwa thead th die einen, tbody th die anderen. Die 3. Spalte der Tabelle enthält Geldbeträge, diese werden rechtsbündig ausgerichtet und die Information über den Zahlungsstatus wird zusätzlich farbig dargestellt.

Beachten Sie: Das Selektieren über strukturelle Pseudoklassen liefert den Vorteil eines schlanken Markups, hat aber den Nachteil, dass bei einer Änderung der Reihenfolge der Spalten auch das CSS angepasst werden muss.

Anpassung für breite Viewports

Diese Tabelle enthält nur sehr kurze Eintragungen in den Feldern. Da wir ihr keine konkrete Breite zugeordnet haben, wird sie nur so breit, wie ihr Inhalt es erfordert. Im Gegensatz zum ersten Beispiel sind für breite Browserfenster deshalb keine Anpassungen notwendig.

Anpassung für schmale und sehr schmale Viewports

Dadurch, dass die Tabelle immer so breit wie der Inhalt ist und man aufgrund der kurzen Eintragungen in die Datenfelder auch keinen Zeilenumbruch generieren sollte, sollte die Tabellenstruktur aufgelöst werden.

Die Schwierigkeit ist hier, dass wir den Tabellenkopf, der ja die einzelnen Spaltenüberschriften enthält, auf alle Datensätze verteilen müssen.

CSS für schmale und sehr schmale Viewports ansehen …
@media screen and (max-width: 42em) {
	table, tbody, tr {
		display: block;
	}
	thead {
		display: none;
	}
	tr:first-child {
		border-top: medium solid lightblue;
	}
	tr {
		border-bottom: medium solid lightblue;
		padding: .5em 2em 1em;
	}
	th::before {
		content: "Rechnung: ";
	}
	td:nth-child(2)::before {
		content: "Datum: ";
	}
	td:nth-child(3)::before {
		content: "Höhe: ";
	}
	td:nth-child(4)::before {
		content: "Status: ";
	}
	td.paid + td::before {
		content: "Zahlungseingang: ";
	}
	tbody th {
		display: block;
		font-weight: bold;
	}
	th a {
		font-weight: normal;
	}
	td {
		display: inline-block;
		min-width: 30%;
		padding: .2em 2em;
		text-align: left;
	}
	td:nth-child(3) {
		text-align: left;
	}
}
@media screen and (max-width: 33em) {
	td {
		display: block;
	}
	tr {
		padding: .5em .5em 1em;
	}
}

Die Tabellenelemente table, tbody und tr machen wir wieder zu Blockelementen, den Tabellenkopf blenden wir aus. Jetzt müssen die Spaltenüberschriften verteilt werden. Dazu erstellen wir before-Pseudoelemente mit den entsprechenden Inhalten. Die Überschriftszellen werden ebenfalls zu Blockelementen formatiert, wohingegen die td-Elemente inline-block-Elemente werden. Durch die Breitenfestlegung passen in diesem Fall zwei td-Elemente nebeneinander.

Wird der Viewport noch schmaler, so werden auch die td-Elemente zu Blockelementen und die Innenabstände der tr-Elemente werden etwas reduziert.

Beachten Sie: Den Verzicht auf Klassen „bezahlen“ wir hier mit der Tatsache, dass an zwei Stellen Inhalte gepflegt werden müssen. Wenn man konsequent mit Klassen arbeiten würde, ließe sich das Verteilen der Spaltenüberschriften über
Beispiel
td::before {
  content: attr(class);
}
umsetzen. Das wiederum hat aber den Nachteil, dass wir die Spaltenüberschrift jeder Tabellenzelle als Klassenname oder data-*-Attribut mitgeben müssen.

Verwendung von custom properties

Seit einiger Zeit können in CSS benutzerdefinierte Eigenschaften verwendet werden. Damit können wir die notwendigen CSS-Angaben als style-Attribut in das HTML-Dokument schreiben

custom properties
<table style="
  --colheader1: 'Rechnung: ';
  --colheader2: 'Datum: ';
  --colheader3: 'Höhe: ';
  --colheader4: 'Status: ';
  --colheader5: 'Zahlungseingang: ';"
>

und die neuen Eigenschaften in der CSS-Ressource verwenden.

custom properties ansehen …
th::before {
  content: var(--colheader1);
}
td:nth-child(2)::before {
  content: var(--colheader2);
}
td:nth-child(3)::before {
  content: var(--colheader3);
}
td:nth-child(4)::before {
  content: var(--colheader4);
}
td.paid + td::before {
  content: var(--colheader5);
}

Auf diese Weise hat man zwar immer noch die Spaltenüberschriften gedoppelt, aber in einem Dokument relativ nah beieinander stehend.

Siehe auch

Weblinks