iX 4/2017
S. 124
Praxis
Webentwicklung/Webdesign
Aufmacherbild

Webseiten mit grid strukturieren

Hinter Gittern

Seit den Frühzeiten des Web wollen Designer Elemente in Zeilen und Spalten positionieren. Bis vor Kurzem mussten sie dafür Umwege über Tabellen oder umfließende Inhalte gehen. Mit neuen CSS-Attributen können sie gitterartige Layouts komfortabel aufbauen.

Seit es das form-Element in HTML gibt, also seit den Kindertagen des Web, beschäftigen sich Gestalter damit, dessen Elemente ordentlich anzuordnen. Ähnlich lange diskutieren sie die Aufgabe, eine Webseite in Kopf-, Fuß-, Navigations- und Hauptbereich aufzuteilen. Die erste Lösung für solche Fragestellungen hieß table: Deren Spalten und Zeilen ließen sich für beliebig komplexe Layouts nutzen, zur Not musste eben eine weitere Tabelle in einer Zelle herhalten. Nach einiger Zeit geriet die Technik jedoch in Verruf, denn mit der Semantik des HTML-Dokuments hatte sie nichts zu tun.

Anschließend kamen Listen zum Einsatz oder div-Elemente, per float, clear: both und festen Breiten zu Höchstleistungen angestachelt. „Div-Suppe“ lautete die abfällige Beschreibung dieser Tricks, die weiterhin wenig zur Semantik der Webseite beitrugen.

Inzwischen hat sich das W3C des Problems angenommen. Die Werte flexbox und grid des display-Attributs sollen in Zukunft semantisch sauberes und gleichzeitig aufgeräumtes Layout erlauben. Im Folgenden wird es um grid gehen. Es ist in Chrome 57, Firefox 52, Opera 43 sowie der Preview-Version von Safari verfügbar. Microsofts Browser IE und Edge haben bislang nur einen älteren Stand der Spezifikation umgesetzt [a], die etwas weniger Möglichkeiten bietet als die aktuelle. Ein Polyfill soll browserneutral alle Grid-Funktionen bereitstellen (siehe „Alle Links“).

Grid-Container als Block oder inline

Für den Aufbau eines Gitters braucht man zunächst einen Container, der die zu positionierenden Elemente aufnimmt. Das kann ein form- oder div-Element sein, per CSS passend konfiguriert:

#container {
  display: grid;
  grid-template-rows: repeat(3, 1.2em);
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
}

Diese Zeilen definieren ein Gitter mit fünf Spalten und drei Zeilen. Das hier verwendete grid erzeugt ein Blockelement, wer ein Inline-Gitter benötigt, benutzt inline-grid.

Alle Spalten sind gleich breit und alle Zeilen gleich hoch. Dafür steht bei den Zeilen die Angabe repeat(3, 1.2em), bei den Spalten jeweils der Wert 1fr. Das verteilt den verfügbaren Platz gleichmäßig auf alle fünf Spalten, alternativ wäre die knappere Notation repeat(5, 1fr) möglich. Breite und Höhe der Rasterzellen kann man in allen üblichen Längeneinheiten angeben, aber px und ähnliche absolute Werte eignen sich für ein anpassungsfähiges Layout nicht.

Die repeat-Funktion erzeugt nicht nur eine festgelegte Zahl von Spalten oder Zeilen, sondern kann alternativ die Anzahl der benötigten Zellen bestimmen. So erzeugt etwa

grid-template-rows:
    repeat(auto-fill, 25ch);

so viele Spalten mit einer Breite von 25 Zeichen, wie der Grid-Container fasst.

Ohne weitere Angaben positioniert ein Gitter seine Kindelemente zeilenweise von links nach rechts und von oben nach unten. Das ist die Voreinstellung row der CSS-Eigenschaft grid-auto-flow. Ist ihr Wert stattdessen column, packt das Grid seine Kinder spaltenweise von oben nach unten und von links nach rechts. Diese Automatismen alleine erlauben allerdings keine besonders komplexen Layouts, bei denen Elemente mehrere Zeilen oder Spalten umfassen.

Solche Anforderungen lassen sich jedoch mit den CSS-Attributen grid-column-start/end und grid-row-start/end erfüllen, etwa so:

#button {
  grid-row-start: 3;
  grid-row-end: 4;
  grid-column-start: 5;
  grid-column-end: 6;
}

Deren Werte stehen nicht für die Spalten- und Reihennummern, sondern für die gedachten Begrenzungslinien dazwischen. Die obigen Zeilen positionieren deshalb den Button in der dritten Zeile und der fünften Spalte des Elternelements. Statt dieser etwas umständlichen Syntax drückt das knappere

grid-column: 5/6
grid-row: 3/4

dasselbe aus. Soll das betreffende Element nur eine Zelle ausfüllen, reicht die Angabe der jeweiligen Anfangswerte aus.

Da bei größeren Grids mit vielen Elementen Zahlen wenig intuitiv sind, lassen sich mit grid-template-areas sprechende Namen für Bereiche des Gitters vergeben. Das klassische Design einer Webseite mit Kopf- und Fußzeile sowie einer Navigation links neben dem Hauptbereich sieht damit im Prinzip so aus:

#main {
  display: grid;
  grid-template-areas: "head head"
         "nav main"
         "foot foot";  }

Benannte Bereiche statt Zahlen

Anschließend platziert man die einzelnen Teile beispielsweise so:

#main > #nav {
  grid-area: nav;
}

Listing 1: Klassische Webseitenaufteilung als grid

<!DOCTYPE html>
<html> <head>
<style>
#container { width: 100%; display: grid; 
grid-template-columns: 10% 90%; grid-template-rows: 2em 1fr 2em; 
grid-template-areas: "head head" "nav main" "foot foot";  }

#head, #foot { background-color: #aaa; }
#head { grid-area: head; }
#foot { grid-area:foot; }
#nav { background-color: #ddd; grid-area: nav; }
#main { background-color: #fff; grid-area: main; min-height: 20em; }

</style>

<title>Webseiten-Aufteilung</title>
</head> <body>
<div id="container">
<div id="head">Kopfzeile</div>
<div id="foot">Fußzeile</div>
<div id="nav">Navigation</div>
<div id="main">Hauptbereich</div>
</div> 
</body> </html>
Mit grid ist eine Webseite schnell in verschiedene Bereiche aufgeteilt (Abb. 1).

Listing 1 zeigt den vollständigen Code, der eine Webseitenaufteilung wie in Abbildung 1 produziert.

Innerhalb von grid-template-areas kann man unbenannte Bereiche mit . markieren. So stellt foot . sicher, dass der Fußbereich nur genauso breit wie die Navigation ist. Soll hingegen die Navigation über die gesamte Höhe der Webseite gehen, müsste man

grid-template-areas: "nav head"
"nav main"
"nav foot"

schreiben.

Bei Bedarf definiert grid-gap einen Abstand zwischen den Zellen des Rasters, alternativ rücken grid-column-gap und grid-row-gap Zeilen und Spalten unterschiedlich weit auseinander.