Über ein Jahr ist es schon her, seit Firefox mit seiner Version 52 als erster Browser weltweit die neue Spezifikation der CSS-Grid implementiert hat.
Seitdem haben fast alle anderen Browser nachgezogen, was vielen Webseiten innerhalb kürzester Zeit erlaubt hat, dieses neue und mächtige Layout-Tool produktiv zu verwenden.
Inhalt
- Statistik
- Struktur und Terminologie einer CSS-Grid
- Tools
- Grid-Container
- Grid-Items
- Ausrichtungs-Optionen (Container und Items)
- Weitere Beispiele
Statistik
Nahezu alle modernen Browser unterstützen die aktuelle Spezifikation der CSS-Grid. Lediglich Internet Explorer sticht heraus, dieser unterstützt dafür aber zumindest die alte Spezifikation und kann daher mit vielen Basis-Anwendungsfällen trotzdem umgehen.
Insgesamt unterstützen laut Can I use mehr als 85 % aller Browser in Deutschland die CSS-Grid, mehr als 80 % sogar komplett ohne Vendor-Präfixe. International sind es sogar noch mehr! (Stand: November 2018)
Struktur und Terminologie einer CSS-Grid
Die CSS-Grid ist praktisch eine Definition von Linien (Tracks), welche Zeilen (Rows) und Spalten (Columns) und daraus entstehende Zellen abgrenzen, in welche Inhalte platziert werden können. Diese Definition passiert auf dem Container. Die Inhalte (Items) verlassen sich zu einem Großteil auf diese Definition und fügen sich einfach in den Container ein, ggf. unter eigener Angabe einer Größe und Position. Die Items können eine oder mehrere Zellen gleichzeitig einnehmen, unter Angabe der Tracks, an denen sie starten und enden. Einen so definierten Bereich nennt man Area.
Der Container kann explizit definieren, wie viele Rows und Columns er hat. Jedoch können dem Container beliebig viele Items übergeben werden. Sollten die definierten Zellen der expliziten Grid dafür nicht mehr reichen, fügt der Container je nach Bedarf implizit weitere Rows und Columns ein. Auch über diese implizite Grid hat man (wenn auch leicht begrenzte) Kontrolle.
Tools
Die Firefox Entwicklertools bieten die aktuell unbestritten besten Werkzeuge zum Umgang mit der Grid. Im Layout-Tab, welcher bislang nur zur Darstellung des Box-Modells (Abstände, Ränder, Größe, Positionierung, … einer Box) gedient hat, zeigt nun auch einen Bereich für Grid-Layout, sofern auf der aktuellen Seite ein solches im Einsatz ist. Die Ansicht muss mit dem Häkchen bei „Gitteransicht hervorheben“ erst für die gewünschte Grid aktiviert werden. Sollten auf der Seite also mehrere Grids sein, kann man auch wählen, welche zu sehen sein soll:
Auswahl der anzuzeigenden Grid. Fährt man mit der Maus über das Fadenkreuz
hinter den Einträgen, wird die entsprechende Grid hervorgehoben.
Ist die Ansicht aktiviert, zeigt Firefox eine Sammlung von Hilfslinien an (in der Farbe, die hinter der gewählten Grid zu sehen ist — diese kann man auch ändern), welche die Grenzen (Tracks) der Grid, einzelner Zeilen/Spalten sowie impliziter und expliziter Grid anzeigen:
Legende:
- Durchgezogene Linien = Start/Ende der expliziten Grid
- Gestrichelte Linien = Tracks der expliziten Zeilen bzw. Spalten
- Gepunktete Linien = Tracks der impliziten Zeilen bzw. Spalten
- Schraffierte Fläche = Abstände zwischen Zeilen/Spalten
Außerdem zeigen die Entwicklertools eine grobe Vorschau des Aufbaus der gesamten Grid:
Die Tracks werden auch nummeriert. Die Anzeige der Nummerierung muss extra aktiviert werden mit einem Häkchen auf „Zeilennummern anzeigen“ (vgl. Bild oben):
Jede Track wird einzeln nummeriert. Der explizite Teil außerdem auch
noch zusätzlich rückwärts nummeriert, beginnend bei -1.
Zu guter Letzt sind auch Namen der Flächen (Areas) zu sehen, wenn diese Anzeige aktiviert ist (Häkchen bei „Bereichsnamen anzeigen“, vgl. Bild oben) und Namen vorhanden sind:
Grid-Container
Den Container definiert man mit den display
-Werten grid
oder
inline-grid
(analog zu block
und inline-block
, table
und inline-table
oder flex
und inline-flex
). Ob man die Block- oder Inline-Variante
verwendet, hat keine Auswirkung auf das innere Verhalten, sondern nur auf den
Fluss des gesamten Containers im Dokument.
Abstände definieren
Der Container kann definieren, wie viel Abstand zwischen allen seinen
Items sein soll. Dies funktioniert ähnlich wie border-spacing
bei
Tabellen: Sämtliche Zeilen und Spalten halten den genannten Abstand zueinander.
Dieser Abstand wird mit der Eigenschaft grid-gap
festgelegt.
Möchte man nur den Abstand zwischen Zeilen definieren, kann man stattdessen
grid-row-gap
verwenden, für Abstände zwischen Spalten grid-column-gap
.
Ein kurzes grid-gap
-Beispiel zum selbst Probieren:
Die neue Einheit fr
Extra für den Einsatz in der Grid wurde eine neue Einheit eingeführt: fr
, kurz
für „fractional“. Dieser Einheit liegt der „übrige“ Platz in der Row
bzw. Column zugrunde. Damit ist der Platz gemeint, welcher abzüglich aller
Items mit fest definierten Größen oder grid-gap
s noch übrig bleibt.
Wenn mehrere Items fr
-Größen zugewiesen bekommen, wird der Platz
gleichmäßig unter ihnen verteilt, proportional zur Größe des Wertes. Zwei
Items mit jeweils 1fr
bekommen gleich viel Platz zugeteilt. Wenn eines
stattdessen 2fr
bekommt und das andere 1fr
behält, bekommt ersteres doppelt
so viel Platz zugeteilt (Verhältnis 2:1).
Insbesondere in Kombination mit grid-gap
ist diese Einheit ein Muss.
Prozentwerte z. B. beziehen diese eben nicht mit ein, daher ergibt sich aus
insgesamt 100 % eine Größe, welche über den Container übersteht.
Ein kurzer Vergleich, wie sich fr
und %
im Vergleich verhalten.
Explizite und implizite Grid
Der Container kann einen Satz von Zeilen und Spalten definieren. Dieser
Bereich ist die explizite Grid. Sollte der Container mehr Items
beinhalten, als er explizite Zellen verfügbar hat, werden die überschüssigen
Items automatisch in der impliziten Grid platziert, d. h. es werden
weitere Zeilen bzw. Spalten angehängt (je nach der angegebenen Richtung in
grid-auto-flow
).
Explizit
Der explizite Teil wird mithilfe der Eigenschaften grid-template-columns
und
grid-template-rows
definiert. Hierin gibt man an, wie viele Spalten/Zeilen
der Container hat und wie breit diese sein sollen.
Beispiel:
grid-template-columns: 50px 50% 1fr;
grid-template-rows: 1fr 1fr;
Hier wurde eine explizite Grid mit 3 Spalten und 2 Zeilen definiert. Die erste Spalte wird 50px breit, die zweite 50% der Gesamtbreite und die dritte nimmt sich den übrigen Platz. Die beiden Zeilen werden gleich hoch.
Es gibt außerdem noch grid-template-areas
, über die ebenfalls die Anzahl von
Zeilen und Spalten angegeben werden, jedoch nicht ihre Breiten. Dafür werden
Namen definiert.
Die Kurzform grid-template
fasst alle 3 Eigenschaften zusammen.
Implizit
Mit ganz ähnlichen Eigenschaften werden auch die Zeilen und Spalten der
impliziten Grid definiert, nämlich grid-auto-columns
und
grid-auto-rows
. Jedoch wird hier nur die Größe einer einzelnen Zeile/Spalte
angegeben, die Anzahl kann nicht vorgegeben werden, da es sich ja um den
impliziten, automatisch ergänzten Teil der Grid handelt.
Beispiel:
grid-auto-rows: 50px;
Hier werden alle automatisch hinzugefügten Zeilen 50px hoch.
Die Grid kann nur in eine Richtung wachsen, sie ergänzt also entweder Zeilen
oder Spalten. Demzufolge wirkt auch immer nur eine der obigen Eigenschaften.
grid-auto-flow
gibt die Richtung der impliziten Grid an.
Möchte man unbedingt alles auf einmal definieren, steht auch die Eigenschaft
grid
für alle oben genannten Eigenschaften zur Verfügung.
Explizite und implizite Grid in Firefox Devtools. Legende:
- Start/Ende der expliziten Grid (durchgezogene Linie)
- Tracks der expliziten Grid (getrichelte Linien zwischen den durchgezogenen)
- Tracks der impliziten Grid (gepunktete Linien nach der durchgezogenen)
- Links stehen die Nummerierungen der Tracks. Implizite Tracks werden ganz normal weiter nummeriert
- Rechts stehen die umgekehrten Nummerierungen der Tracks. Diese werden nur für die explizite Grid angelegt, d. h. Track Nr. -1 ist immer das Ende der expliziten Grid.
Hilfsfunktionen
Eine Grid mit z. B. fünf gleich breiten Spalten kann man mit
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
definieren, jedoch ist das lästige
Tipperei. Hierfür bietet sich auch die Grid-Hilfsfunktion repeat()
an:
grid-template-columns: repeat(5, 1fr);
repeat()
nimmt zwei Werte an: Zuerst die Anzahl der Wiederholungen, danach die
zu wiederholende Größe. In diesem Fall soll also die Größe 1fr
fünfmal
wiederholt werden.
Man kann auch durchaus mehrere Male repeat()
aufrufen:
grid-template-columns: repeat(4, 1fr) repeat(4, 100px);
wird demnach zu
grid-template-columns: 1fr 1fr 1fr 1fr 100px 100px 100px 100px;
.
Manchmal findet man sich auch in der Situation wieder, wo man einer Spalte oder
Zeile zwar den Freiraum geben möchte, ihre Größe anzupassen, jedoch soll sie
ein bestimmtes Minimum nicht unterschreiten, oder ein Maximum nicht
überschreiten. Für diese Fälle wurde die Grid-Hilfsfunktion minmax()
zur
Verfügung gestellt. Diese nimmt ebenfalls zwei Werte an: Der erste ist das
Minimum, der zweite das Maximum. Mindestens einer der beiden Werte muss flexibel
sein (fr
, Prozent, auto
usw.), andernfalls wird einfach der größere Wert
fix gesetzt.
Eine Spalte mit minmax(500px, 1fr)
ist demnach 1fr
breit, aber wird auf
keinen Fall schmaler als 500px. Mit minmax(1fr, 500px)
wird sie dagegen nie
breiter als 500px, kann darunter aber ihre Breite frei bestimmen.
In Kombination mit repeat()
und minmax()
gibt es noch zwei weitere
Grid-Hilfsfunktionen: auto-fit
und auto-fill
. Diese können die Angabe der
Anzahl in repeat()
ersetzen, aber nur wenn die Breite mit minmax()
angegeben
wurde. Mit auto-fit
und auto-fill
ist es möglich, die notwendige Anzahl
automatisch zu berechnen, abhängig davon, wie viele Inhalte zur Verfügung stehen
und welche Größen-Beschränkungen diese haben. Wenn die Inhalte nicht in eine
Zeile/Spalte passen, wird in eine neue umgebrochen. Wenn der Platz größer wird,
dehnen die Inhalte sich aus. Sobald für ein zusätzliches, nicht vorhandenes
Element genug Platz wäre, lässt auto-fill
diesen sogar frei, „reserviert“ ihn
also. auto-fit
tut dies nicht, sondern dehnt die vorhanden Inhalte weiter aus.
Im folgenden Beispiel gibt es sechs Spalten, die nicht schmaler als 100px werden
dürfen. Erst, sobald eine siebte Platz hätte, ist der Unterschied zwischen
auto-fit
und auto-fill
erkennbar:
Laufrichtung der Grid
Standardmäßig ordnet die Grid die Items zuerst von links nach rechts und dann von oben nach unten an.
Dieses Verhalten lässt sich aber auch bewusst mit der Eigenschaft
grid-auto-flow
steuern. Die vier möglichen Werte für diese Eigenschaft sind
row
(das ist der eben beschriebene Standard), column
, row-dense
und
column-dense
. Es funktioniert außerdem noch dense
, dies tut aber das
gleiche wie row-dense
.
Die beiden row
-Werte ordnen zuerst in Zeilen- und dann erst in Spaltenrichtung
an. Sollten die Zeilen nicht genügen, werden neue, implizite angehängt. Die
column
-Werte tun das Gegenteil, sie ordnen zuerst in Spaltenrichtung an und
ergänzen im Fall mangelnden Platzes neue Spalten.
Im Normalfall arbeitet die Grid sich stur Zeile für Zeile bzw. Spalte für Spalte
durch und springt immer weiter, wenn der Platz gefüllt ist bzw. nicht für das
nächste Item ausreicht. Die beiden dense
-Werte erlauben es der Grid, bei
der Anordnung der Items wieder zurück an den Anfang zu springen und nach
der ersten freien übersprungenen Area zu suchen, der groß genug für das
Item ist. Auf diese Weise ist die genaue Reihenfolge der Items nicht
mehr bekannt, aber der Platz in der Grid wird optimal genutzt.
Im Beispiel können die Unterschiede zwischen den vier Varianten ausprobiert werden:
Tracks und Areas benennen
Es ist möglich, den expliziten Tracks und Areas Namen zu geben, um zum Beispiel ihre beabsichtigte Funktion zu verdeutlichen. So kann man eine Area „header“ nennen. Die begrenzenden Tracks bekommen damit automatisch auch Namen: „header-start“ und „header-end“ (gültig für beide Richtungen). Namen können sich auch beliebig überlappen. Beispielsweise kann ein Track gleichzeitig „header-end“ und „main-start“ sein, wenn eine Area „main“ direkt auf den Header folgt.
Um Areas zu benennen, verwendet man grid-template-areas
. Die Notation
dieser Eigenschaft erlaubt es auch schöner Weise, die Areas optisch wie die
Grid auszurichten. Eine Definition von Rows und Columns lässt sich
also auch darüber lösen. Im Beispiel wird eine Grid mit je 3 Rows und
Columns erzeugt. Diese enthalten einen Header, eine Sidebar, einen
Main-Bereich und einen Footer. Möchte man eine Area nicht benennen, kann
diese durch die Notation .
ausgelassen werden.
display: grid;
grid-template-areas: "header header header"
"sidebar main main"
". footer footer";
Ausgabe des obigen Codes, mit angeschalteter Grid-Ansicht in den Firefox
Entwicklertools. Die benannten Areas sind hier sichtbar geschalten.
Man kann auch explizit den Tracks Namen geben. Als wir oben die Breiten
für verschiedene Rows und Columns festgelegt haben, haben wir
genau genommen bestimmt, wie viel Platz der Bereich zwischen zwei Tracks
einnehmen soll. Gedacht steht also tatsächlich da:
[Track] Breite [Track] Breite [Track] …
. An der Stelle, wo die Tracks
gedacht dastehen, kann man sie auch benennen, mit beliebig vielen Namen:
[header-start] Breite [header-end main-start] Breite [main-end …] …
Um obiges Beispiel also nur über benannte Tracks abzubilden, muss man Folgendes definieren:
display: grid;
grid-template-columns: [header-start sidebar-start] 1fr [sidebar-end main-start footer-start] 2fr [main-end footer-end header-end];
grid-template-rows: [header-start] 1fr [header-end sidebar-start main-start] 1fr [sidebar-end main-end footer-start] 1fr [footer-end];
Diese Schreibweise ist aber natürlich um einiges länger und deutlich schlechter verständlich.
Ausrichtungs-Möglichkeiten des Containers
Der Container kann seine eigene Ausrichtung innerhalb seines Elternelements sowie die Ausrichtung aller Items innerhalb der von ihnen belegten Areas verändern. Dazu stehen die CSS-Eigenschaften
justify-content
,align-content
undplace-content
für den Container undjustify-items
,align-items
undplace-items
für die Items
zur Verfügung.
Mehr Informationen dazu in einem späteren Abschnitt.
Grid-Items
Die Items sind direkte Kinder des Containers im Markup. Eine
mögliche Ausnahme zu dieser Regel bietet die recht neue CSS-Eigenschaft
display: contents
, welche dafür sorgt, dass das zugehörige Element aus
dem Markup „verschwindet“.
Die CSS-Eigenschaften float
, display: inline-block
, display: table-cell
,
vertical-align
und alle column-*
-Varianten haben auf einem Grid-Item
keinerlei Wirkung. Dieses Verhalten kann gezielt ausgenutzt werden, um
Fallback-Layouts für ältere Browser ohne Grid-Unterstützung zu definieren.
Die Items suchen sich selbstständig einen passenden Platz in der Grid, welcher ihren Anforderungen entspricht. Diese Aufgabe liegt nicht beim Container.
Platzierung und Größe der Items
Sofern man den Items nichts anderes mitteilt, fügt sich jedes in eine freie Zelle ein. Man kann aber explizit festlegen:
- an welchem (benannten) Track es beginnen und enden soll:
- beginnen:
grid-column-start: <Nummer/Name>; // Spalte grid-row-start: <Nummer/Name>; // Zeile
- enden:
grid-column-end: <Nummer/Name>; // Spalte grid-row-end: <Nummer/Name>; // Zeile
- kombiniert (Schreibweise:
<Start> / <Ende>
):grid-column: <Nummer/Name> / <Nummer/Name>; // Spalte grid-row: <Nummer/Name> / <Nummer/Name>; // Zeile
- beginnen:
- wie viele Zellen es überspannen soll:
grid-column: span <Anzahl>; // Spalte grid-row: span <Anzahl>; // Zeile
Dies ist kombinierbar mit einem Start- oder End-Track, z. B. um am zweiten Track zu starten und 3 folgende Zellen zu überspannen:grid-column: span 2 / span 3; // Spalte grid-row: span 2 / span 3; // Zeile
- welche benannte Area ein Item besetzen soll:
grid-column: <Name>; // Spalte grid-row: <Name>; // Zeile grid-area: <Name>; // grid-column + grid-row in Einem
Nützlich zu wissen: Die automatische Nummerierung der Tracks erfolgt in beide Richtungen. Möchte man also ein Item so platzieren, dass es am letzten Track endet, kann man die Zahl -1 angeben, für den vorletzten Track -2 usw. Dadurch bleibt man flexibel und kann problemlos weitere Rows und Columns einfügen, ohne alles anpassen zu müssen.
Ausrichtungs-Möglichkeiten der Items
Items können ihre eigene Ausrichtung innerhalb der Area, die sie im
Container besetzen verändern. Dazu stehen die CSS-Eigenschaften
justify-self
, align-self
und place-self
zur Verfügung.
Mehr Informationen dazu im folgenden Abschnitt.
Ausrichtungs-Optionen (Container und Items)
Es gibt drei verschiedene Möglichkeiten, den Container oder die Items auszurichten:
- horizontal (CSS-Eigenschaft beginnt mit
justify-
) - vertikal (CSS-Eigenschaft beginnt mit
align-
) - horizontal und vertikal gleichzeitig (CSS-Eigenschaft beginnt mit
place-
)
Der Container kann sowohl sich selbst als auch alle seine Items auf verschiedene Weisen ausrichten. Zusätzlich können die Items für sich selbst noch eine abweichende Ausrichtung angeben:
- kompletten Container ausrichten: CSS-Eigenschaft endet auf
-content
- alle Items (via Container) ausrichten: CSS-Eigenschaft endet auf
-items
- einzelnes Item ausrichten: CSS-Eigenschaft endet auf
-self
Mögliche Werte für die sich ergebenden Eigenschaften wie align-items
oder
place-self
sind:
start
(Inhalt steht am Anfang des Elternelements)end
(Inhalt steht am Ende des Elternelements)center
(Inhalt im Elternelement zentrieren)stretch
(auf volle verfügbare Größe des Elternelements ausdehnen)
Zusätzlich kann der Container für sich selbst noch drei weitere Werte annehmen:
space-around
(Übriger Platz im Elternelement wird gleichmäßig zwischen den Items untereinander und zwischen **Items* und Containerrand verteilt.)space-between
(Übriger Platz im Elternelement wird zwischen den Items untereinander verteilt.)space-evenly
(Wiespace-around
, aber das Verhältnis der Platzverteilung wird angepasst, um insgesamt die Abstände zwischen Items untereinander und am Rand einheitlicher zu gestalten.)
Weitere Beispiele
Flexibles Card-Layout (implizite Zeilen und fr
)
Hier ein Card-Layout, welches alle Cards auf die selbe Größe
bringt, orientiert an der größten Card in der gesamten Grid. Dies funktioniert
mit grid-auto-rows
in der Größe von 1fr
(da die größte Card automatisch
die Verteilung der fr
festlegt).
Zieht man die mittlere Card im Beispiel größer, passt sich die komplette Grid daran an:
Demo Grid Implizit / Fr / Card-Layout
Responsive Umsortierung benannter Areas
Wie bereits oben ausgeführt, lassen sich mit grid-template-areas
leicht
Areas benennen und gleichzeitig dabei das Layout festlegen.
Nichts spricht dagegen, das auch einfach mehrmals für die gleiche Grid zu machen — z. B. einmal für jeden Breakpoint, um so das Layout für alle Größen optimal zu steuern. Beispielsweise:
Mobil:
grid-template-areas: "header header"
"nav nav"
"main main"
"footer footer";
Tablet:
grid-template-areas: "header header header"
"nav main main"
"nav footer footer";
Hier würde ab Tabletgröße die Navigation links vom Hauptinhalt stehen. Zuvor stand sie zwischen Header und Footer.
Sinnvolle Fallbacks für ältere Browser
Die CSS Grid ist ja doch noch ein sehr junges Feature. Auch wenn die Verbreitung mit rasender Geschwindigkeit ansteigt, muss eben doch noch berücksichtigt werden, wie ältere Browser das Layout darstellen sollen ohne Grid.
Eine Zusammenfassung sinnvoller Flexbox-basierter Fallbacks für häufige Grid-Layouts wurden auf www.gridtoflex.com zusammengetragen.