CSS/Tutorials/Grid/Implizite und explizite Erzeugung

Aus SELFHTML-Wiki
< CSS‎ | Tutorials‎ | Grid(Weitergeleitet von CSS/Tutorials/Grid/Grid-Container)
Wechseln zu: Navigation, Suche

In der Einführung in Grid Layout hast du bereits einige flexible Layouts mit Grid kennengelernt. Eventuell hast du gemerkt, dass anders als im pixelgenauen Layout feste Abstände, Breiten- und Höhenangaben oft gar nicht nötig sind!

In diesem Kapitel lernst du, wie du mehrspaltige Layouts mit Grid Layout explizit und implizit erzeugen kannst. Du wirst staunen, was man alles selbst festlegen kann, aber noch mehr, wie viel man eigentlich dem Browser überlassen kann, der dann aus wenigen CSS-Regelsätzen selbst responsive Layouts berechnet und erzeugt!

Grid-Container

Als Grundlage verwenden wir unsere Webseite aus dem HTML-Tutorial.

display: grid

Die Grid-Container werden durch display: grid bzw. inline-grid definiert und können eine Breite, bzw. Mindest- oder Maximalbreite haben.

Beispiel
body {
  display: grid;
  max-width: 99em;
}


Beachte: Dieses Raster wirkt nur auf die Kindelemente des Grid-Containers. Kindelemente der einzelnen Rasterfelder bleiben davon unberührt!

Es gibt noch den Wert subgrid, um verschachtelte Raster zu ermöglichen. Im CSS Grid Layout Module Level 2 ist subgrid ein Wert für grid-template-columns und grid-template-rows, um auch andere als direkte Kindelemente des Grid-Containers in ein Gestaltungsraster zu integrieren.

Erzeugen von Spalten und Zeilen

Das oben erzeugte Raster hätte nur eine Spalte mit untereinanderliegenden Zellen. Damit diese nebeneinander positioniert werden, erzeugen wir nun Spalten.

Einer der faszinierendsten Aspekte ist die Erzeugung der Rasterstruktur. Hier kann bereits im Grid Container, also dem Elternelement, die Größe und Position der einzelnen Rasterelemente (Grid Items) festgelegt werden. Dabei können Anzahl und Größe der Spalten und Reihen

  • mit CSS explizit angegeben oder
  • dies dem auto-placement-Algorithmus implizit überlassen werden.

Explizite Erzeugung

Mit grid-template-columns können Anzahl und Breite der Spalten,
mit grid-template-rows Anzahl und Höhe der Zeilen explizit festgelegt werden.

Grundraster ansehen …
body {
  display: grid;
}

@media (min-width: 30em) { 
	body {
		grid-template-columns: auto auto auto;			
	}
}

Der body wird durch display: grid zu einem Grid Container. Die direkten Kindelemente werden nun innerhalb eines Rasters angeordnet.

Mit grid-template-columns: auto auto auto; werden ab einer Viewportbreite von 30em drei Spalten festgelegt. Der Wert auto sorgt dafür, das sich deren Breite und Höhe an den Inhalt anpassen und die Felder über den verfügbaren Platz verteilt werden.

Die sechs Kindelemente nehmen zwei Zeilen oder Reihen ein.

Es gibt im Beispiel keine explizite Festlegung von Zeilen, diese werden implizit erzeugt. Weitere Elemente werden automagisch in weiteren Zeilen hinzugefügt.

Implizite Erzeugung

In ein HTML-Dokument eingefügter Text bildet einen Textknoten, der aber mangels CSS-Selektor nicht formatiert werden kann. Im Grid Layout wird er als anonymes Rasterelement trotzdem in das Gestaltungsraster eingepasst.

Grundraster mit anonymem Rasterelement ansehen …
<header>
 ...
</header>

<nav>
   ...	
</nav>

Klartext, der ein anonymes Rasterelement bildet.

<aside id="news">
  ...
</aside>

<article>
  ...
</article>

Der auto-placement-Algorithmus parst alle Kindelemente von body, also auch den Textknoten, als Rasterelemente und ordnet sie passend an.

Mehr über den auto-placement-Algorithmus findest du im Kapitel responsive Raster ohne Media Queries.


Wie im oberen Beispiel zu sehen ist, müssen nicht alle Spalten und Zeilen von vornherein definiert werden. Es gibt zwei Situationen, in denen Spalten oder Zeilen automatisch erzeugt werden:

  1. Wenn du Grid Items explizit außerhalb der definierten Spalten und Zeilen platziert, wird das Grid automatisch um so viele Spalten und Zeilen erweitert, dass das Item platziert werden kann. Das heißt: Definiere 3 Spalten mit grid-template-columns, und platziere dann ein Item bei grid-start: 10/span 3;, benötigt das Grid 12 Spalten und bekommt deshalb 9 Spalten hinzu.
  2. Wenn du ein Grid mit – beispielsweise – 3 Spalten und 4 Zeilen definieren, dann aber so viele Grid-Items haben, dass diese 12 Zellen nicht reichen, wird das Grid automatisch erweitert. Ob in diesem Fall Spalten oder Zeilen hinzugefügt werden, richtet sich nach der Eigenschaft grid-auto-flow, deren Standardwert row ist und auf die wir im Artikel über responsive Raster näher eingehen.

Die Breite bzw. Höhe von implizit erzeugten Spalten und Zeilen ergibt sich aus dem Wert der Eigenschaften grid-auto-columns und grid-auto-rows. Fehlen diese Eigenschaften, wird auto verwendet.

Grundraster ansehen …
body {
  display: grid;
  grid-template-columns: auto auto auto; 
}

Der body wird durch display: grid zu einem Grid Container. Die direkten Kindelemente können nun innerhalb eines Rasters angeordnet werden.

Mit grid-template-columns: auto auto auto; werden drei Spalten festgelegt, deren Breite und Höhe sich an den Inhalt anpassen und die über den verfügbaren Platz verteilt werden.

Die sechs Kindelemente nehmen zwei Zeilen oder Reihen ein.


Beachte: Wenn du für grid-row-end oder grid-column-end einen negativen Wert angibst, werden die implizit erzeugten Zeilen bzw. Spalten nicht berücksichtigt. Sind beispielsweise mit grid-template-rows 3 Zeilen definiert, dann endet ein mit grid-row-end:-1 definiertes Grid-Item nach der dritten Grid-Zeile, ganz gleich, ob danach noch automatisch erzeugte Zeilen folgen.

neue Wege bei Längenangaben

Viele Tutorials über Grid Layout verwenden für die Spaltenbreiten Längenangaben mit festen Pixelwerten. Dies ist möglich; verhindert aber einen entscheidenen Vorteil des Grid Layout Moduls:
Anstelle des Entwicklers legt der Browser des Benutzers die Maße anhand des verfügbaren Platzes fest.

Anstelle des Werts auto, der dem Inhalt den minimal benötigten Platz zuweist, können auch eigene Zuweisungen in Form von Längenangaben oder Bruchteilen angegeben werden. Schon bei Flexbox konnte man auf die Berechnung von Prozent-Werten verzichten und der flex-Eigenschaft eine Zahl als Anteil an der verfügbaren Breite zuordnen, aus deren Gesamtwerten dann die verfügbare Breite vom Browser berechnet wurde. Im Grid Layout gibt es hierfür die neue Einheit fr (fraction: engl. für Bruchteil).

Ändere im obigen Beispiel die Werte für die Spalten auf:

Grundraster mit gleicher Breite
 grid-template-columns: 1fr 1fr 1fr ;

Die drei Spalten erhalten jetzt jeweils 1/3 Breite.

repeat() - kürzer und übersichtlicher

Das „CSS-Framework“ Bootstrap besteht aus einem Raster mit 12 Spalten. Hier könnte man mit der repeat()-Funktion auf eine Angabe der Einzelwerte verzichten:

Grundraster mit 12 gleichbreiten Spalten
 grid-template-columns: repeat(12, 1fr);

Die Kindelemente des Rasters verteilen sich auf 12 Spalten. Für unser Beispiel ist das aber noch nicht praktikabel, da die sechs direkten Kindelemente des Rasters jetzt alle nebeneinander und sehr schmal dargestellt werden.

Empfehlung: Verzichte auf Raster mit so vielen Spalten!
Wie du z.B. im Beispiel unten (siehe: fixer Footer) sehen kannst, ist es einfacher, den Spalten unterschiedliche Breiten zu geben, und so das Raster einfacher und übersichtlicher zu halten.

Abstände: margin vs gap

Im Design stoßen die einzelnen Zellen und Rasterbereiche im Allgemeinen nicht direkt aufeinander, sondern haben einen Außenabstand (engl. gutter für Rinne) zwischen Inhalt der Zelle und der eigentlichen Grenze. Dieser Abstand existiert nur zwischen den Zellen; nicht jedoch am äußeren Rand des Rasters. Grid-2.svg

Empfehlung: Realisiere Spalten- und Zeilenabstände nicht durch Leer-Spalten bzw. Zeilen (die dann evtl. versehentlich mit Inhalt gefüllt werden), sondern …
  • klassisch mit margin
  • oder im Grid Layout mit gap.


Abstände mit gap und margin
.gridContainer {
  display: grid;
  gap: 1em;
  margin: 0em;
}
.gridContainer > .kleiner {
  margin: 2em;
}

Der Grid-Container erhält einen Außenabstand (margin) von 0em. Die einzelnen Rasterelemente erhalten jedoch einen Abstand von 1em zwischen den Elementen, nicht jedoch nach außen.

Das Element mit der Klasse .kleiner erhält einen Außenrand von 2em und wird entsprechend kleiner mit einem größeren Abstand zu den umgebenden Rasterlinien dargestellt.

Beachte: Während der Abstand margin für den Außenrand des Containers, bzw einzeln für die einzelnen Rasterelemente festgelegt wird, wirkt gap auf das gesamte Raster.

Die Eigenschaft gap ist die zusammenfassende Eigenschaft der Eigenschaften row-gap und column-gap.[1]

Sie ermöglicht Spalten (englisch: gutter) zwischen den einzelnen Rasterzellen. Am Rand schließen die Rasterelemente bündig mit dem Grid-Container ab.

Im Mehrspaltenlayout mit columns gab es bereits eine Eigenschaft namens column-gap, sodass die Eigenschaft im CSS Box Alignment Module Level 3 ohne Präfixe für Grid Layout, Flexbox und columns vereinheitlicht wurde.

Spalten mit gap ansehen …
main {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 1em 2em;
}

In diesem Beispiel wurde auf einen Rand mit margin verzichtet. Stattdessen werden mit gap: 1em 2em; Spalten zwischen den Rasterelementen festgelegt.


Vergleiche: CSS/Tutorials/Flexbox/Ausrichtung#Spalten (gutter) mit gap


Grundraster mit unterschiedlich breiten Spalten ansehen …
#container {
  display: grid;
  grid-template-columns: repeat(2, 3em 1fr) 10em;
  grid-auto-rows: 5em;
  box-sizing: border-box;
  width: 100%;
  background-color: #866a00 ;
  gap: 0.3em;
  padding: 0.3em;
}

#container > div {
  background-color: gold;
  padding: .5em;
}

Im Raster werden mit grid-template-columns Spalten erzeugt. Dafür wird zum einen die repeat()-Funktion verwendet, um zweimal je eine 3em und eine flexible Spalte (mit 1fr) zu erzeugen. Hinter diesen vier Spalten folgt noch eine einzelne Spalte mit 10em Breite. Die einzelnen Breitenangaben werden mit Leerzeichen voneinander getrennt.

Eine konkrete Zeilendefinition ist nicht vorhanden, dadurch werden Zeilen nach Bedarf erstellt. Ihre Höhe wird mit der grid-auto-rows-Eigenschaft auf 5em festgelegt.

Darüber hinaus wurde mit der Eigenschaft gap ein Spalten- und Zeilenabstand von 0.3em zwischen den Grid-Items festgelegt. Dieser Abstand wird ergänzt durch ein gleich großes Padding des Grid-Containers. Der Effekt ist, dass die etwas dunklere Hintergrundfarbe des Containers zwischen den Grid-Items und um die Items herum sichtbar ist, was zu einem Gittermuster mit einer Balkenbreite von 0.3em führt.

Grid-Items

Das Grid Layout unterscheidet zwischen dem Elternelement Grid-Container und den darin enthaltenen Rasterelementen (Grid-Items). Wie im letzten Beispiel schon angerissen, können die Grid Items beliebig im Raster platziert und dimensioniert werden:


Unsere Webseite soll ja eben nicht aus gleichgroßen Blöcken bestehen. Deshalb sollen im nächsten Schritt individuelle Festlegungen für jedes einzelne Rasterelement getroffen werden. Die Rasterelemente können einzelne Zellen oder aber einen Rasterbereich (grid area) über mehrere Felder einnehmen.

Der folgende Abschnitt mag verwirrend erscheinen. Grund ist, dass in einer Zeile CSS zwei verschiedene Schritte durchgeführt werden:

  1. Linien werden als Start unserer Rasterelemente selektiert.
  2. Die Rasterelemente erhalten mit Berechnungen zu anderen Rasterlinien ihre Größe.

Anfangs- und Endlinien festlegen

Grid-1.svg

Mit den Eigenschaften

sowie

können Anfangs- und End-Rasterlinien festgelegt werden, die damit die Größe und Position innerhalb der grid row bestimmen.

Übersichtlicher ist die Verwendung der zusammenfassenden Eigenschaften (shorthand properties) grid-column und grid-row:

Die grid-column-Eigenschaft ist die Zusammenfassung der Eigenschaften grid-column-start und grid-column-end, die durch den Slash getrennt werden.

Mögliche Angaben sind:

  • grid-column: 1 / 6;: Das Rasterelement erstreckt sich von der ersten bis zur 6. Rasterlinie.
  • grid-column: 1 / -1;: Es sind auch negative Werte möglich. Das Rasterelement erstreckt sich von der ersten bis zur letzten Rasterlinie (automatisch erzeugte Rasterlinien zählen dabei allerdings nicht mit).
  • grid-column: 1 / span 5;: Das Rasterelement erstreckt sich von der ersten Rasterlinie über 5 Zellen hinweg.
  • grid-column: span 5;: Das Rasterelement erstreckt sich über 5 Zellen hinweg. Ein fester Anfang ist nicht vorgegeben.


Grundraster mit festgelegtem Rasterbereich für den header ansehen …
body {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
}

header {
  grid-column: 1 / 6;
  grid-row:    1 / auto;			
}

nav {
  grid-column: 1 / span 5;
  grid-row:    2;		
}

Ausgangspunkt ist wieder unser 5-spaltiger Raster.

Für den header legen wir mit grid-column fest, dass er in der ersten Spalte beginnen und dann am Ende der 5. Spalte ( also an der 6. Rasterlinie) enden soll. grid-row legt fest, dass er von der ersten horizontalen Rasterlinie beginnen soll. Der Wert auto wird als span mit einem Wert von 1 berechnet, sodass das Element eine Zeile hoch ist.

Die Navigation beginnt in der ersten Spalte und erstreckt sich durch das Schlüsselwort span über 5 Spalten. Die vertikale Positionierung beginnt in der 2. Zeile und ist eine Zeile hoch. Da der Defaultwert für grid-row-end ja auto beträgt, muss er nicht mehr explizit erwähnt werden.

Die anderen vier Rasterelemente werden als schmale Spalten in der dritten Zeile dargestellt.


Empfehlung: Öffne das Beispiel unter [So sieht's aus]. Bei einem schmalerem Viewport verteilen sich die 4 verbliebenen Rasterelemente auf den verfügbaren Raum, bei breiteren Viewports bleibt rechts eine Spalte frei.
Verändere die Werte für grid-column und grid-row und beobachte die Veränderungen.

eigene Rasterbereiche

In einem weiteren Schritt werden nun für alle Kindelemente des Rasters eigene Rasterbereiche festgelegt:

Grundraster mit festgelegten Rasterbereichen ansehen …
body{
  display: grid;
  grid-template-columns: repeat(5, 1fr);
}

header {
  grid-column: 1 / 5;
  grid-row:    1 / 2;			
}

nav {
  grid-column: 1 / 2;
  grid-row:    2 / 4;					
}

article {
  grid-column: 2 / 4;
  grid-row:    2 / 4;					
}

aside {
  grid-column: 5 / 6;
}

footer {
  grid-column: 1 / 6;
  grid-row:    4 / 5;					
}

Für jedes Kindelement im Raster wird mit grid-column und grid-row ein Rasterbereich (grid area) festgelegt.

Fünf Dinge fallen auf:

  • Der article endet an der 4. Linie, die aside-Boxen beginnen aber erst bei der 5. Linie. Der dazwischenliegende Platz bleibt (im Unterschied zu einer Umsetzung mit Flexbox) leer.
  • Die aside-Boxen erhalten keine Festlegung der Höhe und nehmen dann den Defaultwert von einer Spanne / der Höhe einer Zelle ein. Die zweite aside-Box wird automatisch in einer neuen Zelle unterhalb der ersten platziert.
  • Die Positionierung erfolgt unabhängig von der Reihenfolge im HTML-Markup. (Allerdings sollte dies aus Zugänglichkeitsgründen nur in Ausnahmefällen erfolgen.)
  • Während die Spalten mit grid-template-columns: repeat(5, 1fr); festgelegt wurden, werden die Zeilen auch ohne Festlegung automatisch gebildet.
    Empfehlung: Entferne die Wertzuweisung für grid-template-columns und beobachte, was passiert.
  • Alle Rasterelemente haben einen margin von .5em, sonst würden die Elemente aneinanderstoßen. (Dies kann aber auch mit gap erreicht werden.)


Beachte: Viele der oben noch verwendeten Festlegungen sind gar nicht nötig: Wenn ein Element nur eine Spalte breit oder eine Reihe hoch sein soll, kann die Festlegung auch weggelassen werden.
Empfehlung: Verwende solche festen Positionierungen nur sparsam.
Nutze die impliziten Algorithmen des Grid Layout!
Der Browser verteilt die Elemente ganz von selbst im verfügbaren Platz!

grid-area

Ein Blick in den Seiteninspektor des Firefox verrät, dass diese expliziten Festlegungen vom Browser in der zusammenfassenden Eigenschaft grid-area notiert werden. Dabei werden die Werte von grid-row-start, grid-column-start, grid-row-end und grid-column-end jeweils mit einem Slash (/) notiert:

Rasterbereiche mit grid-area
header {
  grid-area:  1 / 1 / 2 / 6;			
}

/* übersichtlichere Alternative */

nav {
  grid-area: 2 / 1 / auto / span 1;				
}

Kürzer, aber auch unübersichtlicher. Wenn das Layout steht, könnte man die Eigenschaften so zusammenfassen. Durch die Angabe der Schlüsselworts span für die Breite oder Höhe könnte man wieder Übersichtlichkeit gewinnen.

negative Werte

Wenn man Elemente über die gesamte Breite (oder bis zum Ende) des Rasters spannen will, musst du nicht die Anzahl der Zellen zählen, bzw. den Wert bei einer Änderung der Anzahl der Spalten ändern. Ein negativer Wert beginnt mit der Zählung von rechts, sodass das Element dann alle Spalten überspannt:

Elemente über die gesamte Breite
body{
  display: grid;
  grid-template-columns: repeat(5, 1fr);
}

header {
  grid-column: 1 / -1;
  grid-row:    1 / 2;			
}

Der header beginnt an der ersten Rasterline. Das Ende befindet sich durch den Wert -1 am Beginn von rechts, also dem Ende des Rasters.

Anwendungsbeispiele

feststehender Footer

Grundraster ansehen …
body {
	display: grid;
	grid-template-columns: 1fr 3fr 1fr;
	grid-template-rows: min-content 1fr 1fr min-content;
	gap: .5em;
	min-height: 100vh;
}
...
footer {
  grid-column: 1 / span 3;
  grid-row:    4;					
}

Der body wird durch display: grid zu einem Grid Container. Die direkten Kindelemente können nun innerhalb eines Rasters angeordnet werden.

Mit grid-template-columns: 1fr 3fr 1fr; werden nun drei Spalten festgelegt, die den verfügbare Breite im Verhältnis der Bruchteile (hier 1 : 3 : 1) untereinander aufteilen.

Mit grid-template-rows: min-content 1fr 1fr min-content; werden nun vier Zeilen festgelegt. Während die obere und untere Zeile sich mit min-content anhand des vorhandenen Inhalts orientieren, teilen die beiden mittleren Zeilen den verfügbaren Raum unter sich im Verhältnis der Bruchteile fr (hier 1:1) unter sich auf.

Die sechs Kindelemente (Grid Items) werden mit grid-column und grid-row passend positioniert; der footer nimmt zum Beispiel den Raum zwischen 4. und 5. horizontaler Rasterlinie (also die 4. Zeile) ein. In grid-column ist festgelegt, dass er an der ersten vertikalen Rasterlinie beginnt und (alle) 3 Spalten überspannt.


Definitionsliste nebeneinander

Die Elemente von Definitions- oder Beschreibungslisten werden in der browsereigenen Darstellung untereinander angezeigt. Das Platzieren der Blöcke kann schwierig werden, da bei mehreren dd-Elementen ein gemeinsames Elternelement fehlt. Mit Grid Layout ist es möglich, Definitionslisten in ein kompaktes Raster zu fassen.

Formular ansehen …
dl {
  display: grid;
  grid-template-columns: auto 1fr;
  max-width: 18em;
  margin: 1em;
  line-height: 1.4;
}
dt {
  grid-column: 1;
  font-weight: bold;
}
dd {
   grid-column: 2;
 }

Die Beschreibungsliste dl besteht aus zwei Spalten, deren erste sich am vorhandenen Inhalt ausrichtet. Die zweite nimmt den verfügbaren restlichen Raum ein.

Der dt-Ausdruck beginnt an der ersten Rasterlinie, also in der 1. Spalte, die Beschreibungen dd immer in der zweiten.

Fazit

Ich habe nun drei Jahre Erfahrung mit dem mittlerweile nicht mehr ganz neuen Grid Layout:

Der stärkste Vorteil des Grid Layout ist seine Flexibilität, mit der die Elemente im Raster verteilt werden. Bei einigen Elementen mit viel Inhalt ist es wichtig und richtig, sie über mehrere Zellen erstrecken zu lassen.

Generell sollte man aber (fast) alles den Browser machen lassen. Genau wie eine pixelgenaue Positionierung wenig sinnvoll ist, so wenig nützen zu viele Angaben zur genauen Position für alle Rasterelemente. Besser als feste Pixelangaben sind relative Angaben in rem oder em, noch besser sind Angaben wie min-content oder fit-content.

Empfehlung:
  • Verzichte auf feste Pixelwerte. Auch wenn viele Tutorials diese verwenden, ist dies in der Praxis nicht zu empfehlen, da so die Vorteile der flexiblen Positionierung und Ausrichtung nicht vollständig zur Wirkung kommen.
  • Verwende, wie in diesem Kapitel, die relativen Maße em und vh, sowie den Bruch-/Anteil fr.
    So wird die Rechnerei, wie viel Platz denn nun verfügbar ist, dem Browser überlassen.

Im nächsten Kapitel erfährst du, wie du die Raster (bzw. die Anzahl der Felder pro Reihe) ohne media queries responsiv gestalten kannst.

--Matthias Scharwies (Diskussion) 06:33, 14. Mär. 2020 (CET)

  1. MDN: gap (grid-gap)