CSS/Tutorials/Layout mit Grid

Aus SELFHTML-Wiki
< CSS‎ | Tutorials
Wechseln zu: Navigation, Suche

In diesem Artikel lernen Sie, wie Sie Schritt für Schritt mehrspaltige Layouts mit dem neuen Grid Layout gestalten können. Hier ist es möglich, die Elemente beliebig zweidimensional anzuordnen.

Dabei entwickeln wir ein responsives Layout, das sich individuell an jeden Viewport anpassen kann. Die wenigen Browser, die Grid Layout nicht unterstützen, ordnen die Elemente der Webseite untereinander an. Alternativ können Sie die Festlegungen für das Grid Layout innerhalb einer @supports -Regel definieren und ein herkömmliches Design als Fallback anbieten.


Hinweis

Adventskalender 2017

Dieser Artikel ist der Beitrag zum 12. Dezember.

Zurück zum

Ein Raster[Bearbeiten]

Als Grundlage verwenden wir unsere Webseite aus dem HTML5-Tutorial; weiterführende Informationen über nötige Grundeinstellungen erhalten Sie im Artikel CSS/Tutorials/mehrspaltige Layouts.

Beispiel: 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.

Anstelle des Werts auto, der dem Inhalt den minimal benötigten Platz zuweist, können Sie auch eigene Zuweisungen in Form von Längenangaben oder Bruchteilen angeben. 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).

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

Beispiel: Grundraster mit gleicher Breite
 grid-template-columns: 1fr 1fr 1fr ;
Die drei Spalten erhalten jetzt jeweils 1/3 Breite.


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:

Beispiel: 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.

Die Rasterelemente[Bearbeiten]

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

Anfangs- und Endlinien festlegen[Bearbeiten]

Mit den Eigenschaften grid-row-start, grid-column-start, sowie grid-row-end und grid-column-end können Sie Anfangs- und End-Spalte, bzw. Zeile und damit die Größe und Position innerhalb der grid row festlegen. Übersichtlicher ist die Verwendung der zusammenfassenden Eigenschaften (shorthand properties) grid-column und grid-row:

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

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

nav {
  grid-column: 1 / span 12;
  grid-row:    2;		
}
Ausgangspunkt ist wieder unser 12-spaltiger Raster.

Für den header legen wir mit grid-column fest, dass er in der ersten Spalte beginnen und dann am Ende der 12. Spalte ( also an der 13. 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 12 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.

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

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

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

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

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

aside {
  grid-column: 12/ 13;
}

footer {
  grid-column: 1 / 13;
  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 11. Linie, die aside-Boxen beginnen aber erst bei der 12. 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 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(12, 1fr); festgelegt wurden, werden die Zeilen auch ohne Festlegung automatisch gebildet.
    Empfehlung: Entfernen Sie die Wertzuweisung für grid-template-columns und beobachten Sie, was passiert.
  • Alle Rasterelemente haben einen margin von 10px, sonst würden die Elemente aneinanderstoßen. (Dies kann aber auch mit grid-gap erreicht werden.)

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:

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

*/ ü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.

Achtung!

Die Browser IE10, IE 11 und Edge 12-15 haben eine ältere Version der Spezifikation implemetiert, die diese und andere zusammenfassenden Eigenschaften nicht kennen. Auch die folgenden Beispiele funktionieren dort nicht.

negative Werte[Bearbeiten]

Wenn Sie Elemente über die gesamte Breite (oder bis zum Ende) des Rasters spannen wollen, müssen Sie 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:

Beispiel: Elemente über die gesamte Breite
body{
  display: grid;
  grid-template-columns: repeat(12, 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.

benannte Linien[Bearbeiten]

Bei jedem Raster stellt sich die Frage nach der optimalen Anzahl und der Identifizierung der einzelnen Rasterelemente. Im Schach werden die Spalten mit den Buchstaben a-h, die Reihen oder Zeilen mit 1-8 gekennzeichnet. Im Printbereich hat sich ein 12er-Raster wie oben bewährt, da es durch 2,3,4,6 teilbar ist und so viele verschiedene Kombinationen erlaubt.

Auch wenn das Rechnen mit Zwölfteln, bzw. Bruchteilen einfacher ist, als das ständige Zusammenrechnen von Breiten, Innen- und Außenabständen - schlimmstenfalls in verschiedenen Maßeinheiten, bietet Grid Layout eine Alternative, die ganz ohne Mathematik auskommt. Anstelle von numerischen Werten können Sie den Rasterlinien auch semantische Namen geben, die das Positionieren der einzelnen Elemente ganz ohne Berechnungen erlaubt:

Beispiel: Grundraster mit benannten Linien ansehen …
body {
  display: grid;
  grid-template-columns: 1fr [main-links] 2fr [main-rechts] 1fr;
  grid-template-rows: min-content [main-oben] 1fr 1fr  [main-unten] min-content;	
}
Der body wird mit dem schon bekannten grid-template-columns in 3 Spalten eingeteilt, wobei die mittlere durch den Wert 2fr doppelt so breit ist. Die Werte für die Breiten werden jetzt nicht durch Leerzeichen, sondern durch in eckigen Klammern befindliche Liniennamen getrennt.
Auch für die Zeilen werden mit grid-template-columns Liniennamen vergeben. Hier fällt auf, dass die oberste und unterste Reihe durch das Schlüsselwort min-content so klein wie möglich dargestellt werden sollen.
header {
	grid-column-start: 1; 
	grid-column-end: rand-rechts;
}

nav {
	grid-row: main-oben / main-unten;		
				
}

article {
	grid-column-start: main-links;
	grid-row: main-oben / main-unten;			
}

aside {
	grid-column-start: main-rechts;
}

footer {
	grid-column: 1 / rand-rechts;
	grid-row-start: main-unten;				
}
Die Kindelemente erhalten nun ihre gewohnten Postionierungen. Anstelle eines Ausrechnens der Breiten und Höhen werden als Beginn und Ende der Elemente aber meist die benannten Linien verwendet.
Beachten Sie: Viele der oben noch verwendeten Festelgungen sind gar nicht nötig: Wenn ein Element nur eine Spalte breit oder eine Reihe hoch sein soll, kann die Festlegung auch weggelassen werden.

So werden die aside-Boxen in der rechten Spalte rechts des article-Elements positioniert. Die Höhe und vertikale Positionierung ist nicht festgelegt und wird von Browser bestimmt. Bei nur einer aside-Box würde sich eine Lücke ergeben - eine dritte aside-Box würde in der rechten Spalte unterhalb des footers dargestellt werden.

Wenn Sie auf die eigentlich nicht nötige Festlegung grid-row-start: main-unten; für den Footer verzichteten, würde in zusätzliche aside-Box oberhalb des footers angeordnet werden.
Empfehlung: Nutzen Sie die Möglichkeiten des Grid Layout und verwenden Sie die Möglichkeiten der Positionierung nur sparsam. Der Browser verteilt die Elemente ganz von selbst im verfügbaren Platz!


Rasterbereiche[Bearbeiten]

In vielen Tutorials wird ein Vorteil von Grid Layout herausgestellt: Die Positionierung kann auch allein im Elternelement des Grid Containers vorgenommen werden:

Beispiel: Grundraster mit festgelegten Rasterbereichen ansehen …
body{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-areas: "head head head head"
                       "nav  main main news"
                       "nav  main main aside" 
					   "foot foot foot foot";
}

header {
  grid-area: head;	
}

nav {
  grid-area: nav;			
}

article {
  grid-area: main;				
}

aside {
  grid-area: aside;
}
		
#news {
  grid-area: news;			
}

footer {
  grid-area: foot;				
}
Die Kindelemente (Grid Items) erhalten in der grid-area-Eigenschaft einen Namen, der dann in grid-template-areas in einem Schema wieder auftaucht. In diesem Schema werden wie in einer ASCII-Zeichung die einzelnen Elemente des Rasters aufgeführt. Allerdings müssen die beiden aside-Boxen jetzt gesondert aufgeführt werden, da sie sich sonst überschreiben würden.

Mit dieser Methode können Anpassungen an andere Viewports sehr schnell vorgenommen werden:

Beispiel: responsives Raster ansehen …
body{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-areas: "head head "
                       "nav  nav"
                       "main main"
                       "news aside" 
					   "foot foot";
}

@media (min-width: 30em) { 
  body{
    grid-template-columns: repeat(3, 1fr);
    grid-template-areas: "head head head "
                         "nav  news aside"
                         "main main main" 
		  			     "foot foot foot";
 }
}

@media (min-width: 50em) { 
  body{
    grid-template-columns: repeat(4, 1fr);
    grid-template-areas: "head head head head"
                         "nav  main main news"
                         "nav  main main aside" 
		  			     "foot foot foot foot";
 }
}
Die Kindelemente sind bis auf die beiden aside-Boxen untereinander angeordnet Bei einer Viewportgröße von mindestens 30em greift die media query und schaltet die entsprechenden Werte für grid-template-areas um, sodass Navigation und aside-Boxen nebeneinander dargestellt werden. Ab 50em Breite wird das „normale“ Desktop-Layout erzeugt.

feststehender Footer in der Desktopansicht[Bearbeiten]

Was im Grid Layout anfangs sehr verwirrt, ist die Vielzahl von gleichklingenden Eigenschaften. So wie grid-row-start zu shorthand grid-row und dann sogar zu grid-area zusammengefasst werden kann, können die Eigenschaften grid-template-columns, grid-template-rows und grid-template-areas in der zusammenfassenden Eigenschaft grid-template notiert werden. Aber auch diese ist Teil der zusammenfassenden Eigenschaft grid:

Beispiel: responsives Raster mit feststehenden Footer in der Desktopversion ansehen …
body{
  min-height: 100vh;
  display: grid;
  grid: "head head "
        "nav  nav"
        "main main"
        "news aside" 
        "foot foot"
        / 1fr 1fr;
}

@media (min-width: 30em) { 
  body{
    grid: "head head head "
          "nav  news aside"
          "main main main" 
          "foot foot foot"
          / 1fr  1fr 1fr;
 }
}

@media (min-width: 50em) { 
  body{
    grid: "head head head head" 150px
          "nav  main main news"   1fr
          "nav  main main aside"  1fr
          "foot foot foot foot" min-content
          / 1fr  1fr  1fr  1fr;
 }
}
In diesem Beispiel ist der body mit einer min-height von 100vh ausgestatttet, sodass er auch auf großen Monitoren immer bis ganz nach unten reicht.

Die Festlegungen der grid-template-areas und grid-template-columns werden nun in der zusammenfassenden Eigenschaft grid kürzer notiert. Beachten Sie, dass die Verwendung der repeat()-Funktion hier nicht möglich ist und die Spalten nacheinander ausgeschrieben werden müssen.

In den beiden schmalen Ansichten werden die Zeilen implizit erzeugt, in der dritten Ansicht erhält die ASCII-Zeichnung des Rasteraufbaus auf der rechten Seite Höhenangaben. Während der header einen festen Werte erhält, passt sich der footer mit min-content an den vorhandene Inhalt an und kann so nie das Layout zerschießen. Die beiden mittleren Zeilen verteilen sich über den verfügbaren restlichen Raum.

Responsivität[Bearbeiten]

Die oben gezeigte Möglichkeit demonstriert, wie Sie mit der Abfrage von Medienmerkmalen mit media queries Raster an die verfügbare Viewportbreite anpassen können. Dabei wird häufig immer noch zu sehr an eine mögliche Viewport-Breite anstelle des Platzbedarfs für die Inhalte gedacht.

Oft gibt es jedoch Anwendungsfälle, inden Sie kein Raster vorgeben müssen, sondern die Abmessungen durch die Zuweisung von Mindest- und Maximalbreiten so festlegen können, dass sich die Rasterelemente immer passsend anordnen.

Vielen Dank an Gunnar Bittersmann für die Beispiele!

Textblöcke automatisch anordnen[Bearbeiten]

Die Erklärung der Menschenrechte besteht aus 30 gleichberechtigten Artikeln. Sie sollten in Blöcken nebeneinander stehen, wenn die Viewportbreite dies zulässt. Die Größe der Blöcke wird aber nur durch den Inhalt bestimmt.

Beispiel: flexibles Grid Layout ohne media queries ansehen …
main {
  display: grid;
  grid-gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(20em, 1fr));
  color: black;
  font: 1em/1.3 Cambria, serif;
}

main > section {
  padding: 1rem;
  background: hsl(220, 80%, 90%);
}
Für die 30 section-Blöcke werden mit grid-template-columns Spalten erzeugt. Dabei werden mit der repeat()-Funktion über das autofill-Schlüsselwort so oft wie nötig Spalten mit einer durch die minmax(20em, 1fr)-Funktion ermittelten Breite von mindestens 20em Breite und maximal einem Bruchteil erzeugt.

Ein Panorama mit zentrierter Überschrift[Bearbeiten]

Ein Panoramabild soll über der gesamten Breite des Viewports erscheinen, die dazugehörende Überschrift jedoch zentriert bis zu einer noch lesbaren Breite:

Beispiel: flexibles Grid Layout ohne media queries ansehen …
main {
  display: grid;
  grid-template-columns: [full-start] minmax(1em, 1fr) [text-start] minmax(0, 40em) [text-end] minmax(1em, 1fr) [full-end];
}

main > * {
  grid-column: text;
  margin: 0.7rem 0;	
}

h2 {
  font-size: 1.4em;
  line-height: 1.1;
}

img {
  grid-column: full;	
  width: 100%;
}
In grid-template-columns wird festgelegt, dass main aus 3 Spalten besteht, deren Rasterlinien mit full-start, text-start sowie text-end und full-end benannt sind. Die Breite wird über die minmax()-Funktion auf mindestes 1em und maximal ein Bruchteil für die beiden äußeren, und auf maximal 40em für die innere Text-Spalte festgelegt.

Mit dem Kindselektor main > * werden alle Kinder mit grid-column : text in die mittlere Spalte platziert, da grid-column-start die text-start-Rasterlinie und grid-column-end die text-end-Rasterlinie ist.

Für das Bild werden mit grid-column : full die full-start und full-end-Rasterlinien als Start- und Endpunkte genommen.

Siehe auch[Bearbeiten]

Weblinks[Bearbeiten]