Grid Layout/Responsive Raster ohne Media Queries

Aus SELFHTML-Wiki
Grid Layout(Weitergeleitet von Masonry)
Wechseln zu: Navigation, Suche

In der Einführung in Grid Layout hast du bereits erste flexible Layouts kennengelernt. Dabei hast du vielleicht bemerkt, dass feste Breiten, Höhen und Abstände oft gar nicht nötig sind.

In diesem Kapitel lernst du, wie du mit Grid Layout mehrspaltige Layouts erstellen kannst – sowohl mit explizit definierten als auch mit automatisch erzeugten Rastern.

Während im Printdesign oder in „CSS-Frameworks“ wie bootstrap meist ein festes Gestaltungsraster vorgegeben wird, kann der Browser bei Grid viele Aufgaben selbst übernehmen – oft sogar ganz ohne Media Queries.[1][2]

Das erste Raster

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

Drei Spalten mit Grid

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

Grundraster – noch ohne Spalten
body {
  display: grid;
  max-width: 99em;
}

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

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: 1fr 1fr 1fr;			
	}
}

Der body wird durch display: grid zu einem Grid Container. Seine direkten Kindelemente werden nun in einem Raster angeordnet.

Ab einer Viewportbreite von 30em erzeugt grid-template-columns: 1fr 1fr 1fr; drei gleich breite Spalten. Die Einheit fr (fraction) verteilt den verfügbaren Platz gleichmäßig auf die Spalten.

Da sechs Elemente vorhanden sind, entstehen automatisch zwei Zeilen. Diese Zeilen werden nicht ausdrücklich definiert, sondern von Grid bei Bedarf erzeugt. Man spricht von einem impliziten Raster.

Beachte: Dieses Raster wirkt nur auf die direkten Kindelemente des Grid-Containers. Inhalte innerhalb dieser Elemente werden dadurch nicht automatisch zu Grid-Items.

Explizite und implizite Raster

Grid kann Raster auf zwei Arten erzeugen:

  • explizit, indem Spalten und Zeilen mit CSS festgelegt werden,
  • implizit, indem der Browser bei Bedarf weitere Rasterspuren automagisch anlegt.[3]
Grundraster mit anonymem Rasterelement ansehen …
body{
	display: grid;
	grid-template-columns: auto auto auto;	
	grid-auto-rows: 12em;	
	gap: 1em;			
}

Wenn man das Raster anschaut, fällt auf: 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.

Wenn ein Grid mehr Inhalte enthält, als in eine Zeile passen, erzeugt der Browser automatisch weitere Zeilen (das sogenannte implizite Raster).

Mit grid-auto-rows: 12em erhalten alle automatisch erzeugten Zeilen eine feste Höhe von 12em.

Enthält ein Rasterfeld mehr Inhalt, als in diese Höhe passt, kann der Inhalt überlaufen.

Abstände: margin vs gap

Im Design stoßen die einzelnen Zellen und Rasterbereiche im Allgemeinen nicht direkt aufeinander, sondern haben einen Außenabstand zwischen Inhalt der Zelle und der eigentlichen Grenze. Dieser Abstand existiert nur zwischen den Zellen; nicht jedoch am äußeren Rand des Rasters.

Im Rasterdesign gibt es meist Abstände zwischen den einzelnen Zellen oder Bereichen. Diese Zwischenräume nennt man im Layout oft gutter (engl.für Rinne).

Wichtig ist: Diese Abstände liegen nur zwischen den Rasterelementen, nicht am äußeren Rand des Grids.

Für solche Abstände stellt Grid die Eigenschaft gap zur Verfügung. Im Gegensatz zu margin wirkt gap nur innerhalb des Rasters und beeinflusst nicht die Außenabstände der einzelnen Elemente.


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.

Flexible Größen mit minmax()

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.

Damit der autoplacement-Algorithmus seine volle Wirkung entfalten kann, muss die Breite der Spalten flexibel sein. Bisher wurde dies bei fester Spaltenanzahl mit der Einheit fr erledigt. Nun sollen die Spalten eine feste Mindestgröße, aber auch keinen überschüssigen Raum in Form eines leeren Rands haben.

Voilà: Die minmax()-Funktion erlaubt es anstelle von festen oder relativen Längenangaben einen Mindest- und einen Maximalwert anzugeben:

responsives Raster mit minmax() ansehen …
body {
  display: grid;
  grid-template-columns:
    minmax(10em, 12em)
    1fr
    minmax(10em, 12em);
  gap: 1em;			
}

Mit minmax() begrenzen wir die Spalten, aber lassen dem Browser trotzdem Spielraum. Die beiden äußeren Spalten werden mindestens 10em und höchstens 12em breit. Der verbleibende Raum wird für die mittlere Spalte verwendet. Auf schmalen Viewports scheinen die drei Spalten gleichbreit, auf großen Viewports hat der Inhalt des article mehr Platz.

Trotzdem ist dieses Raster noch nicht optimal: Die Mindestbreite beträgt ja 30em Breite, bei schmalen Viewports entstehen Scrollbalken.

auto-fit – Der Browser entscheidet die Spaltenanzahl

Bequemer als die Lösung mit media queries ist es allerdings, mittels des Schlüsselworts auto-fit den Browser die Anzahl der Spalten automatisch festlegen zu lassen[4]:

ein gefülltes Raster ansehen …
body{
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10em, 1fr));
  gap: 1em;
}

Als Wert für grid-template-columns gibt es nun zwei CSS-Funktionen:

minmax(12em, 1fr)

Eine Spalte ist:

  • mindestens 12em breit
  • maximal flexibel (1fr)


repeat(auto-fit, ...)

Die repeat()-Funktion, die nun über den ersten Parameter auto-fit so viele Spalten wie nötig erzeugt.

Nicht mehr du definierst das Layout für jede Bildschirmgröße – der Browser erledigt das!

Dies ist das Entscheidende am Grid Layout!

Vorher:

  • Du kontrollierst alles mit festen Längen- und Breitenangaben.

Jetzt:

  • Du definierst nur Regeln.
  • Der Browser baut das Layout.

Wenn der Browser das Layout so gut selbst erzeugen kann — brauchen wir dann überhaupt noch Media Queries?

Der Browser kann mit Grid bereits erstaunlich viele Layouts automatisch erzeugen. Dennoch gibt es Situationen, in denen Elemente gezielt platziert oder für bestimmte Bildschirmgrößen neu angeordnet werden müssen.

Elemente gezielt platzieren

Bisher wurden alle Rasterelemente(Grid-Items) automatisch im Grid angeordnet. Das ist für einfache Layouts oft ausreichend, für eine typische Webseite jedoch nicht.

Rasterlinien nutzen

Der Header soll die gesamte Seitenbreite einnehmen. Dazu können Grid-Items gezielt auf bestimmte Rasterlinien gesetzt und über mehrere Spalten oder Zeilen hinweg aufgespannt werden.

Jede Spalte und jede Zeile eines Grids wird durch Rasterlinien begrenzt. Diese Linien dienen als Bezugspunkte für die Platzierung der Elemente. Mit Start- und Endlinien lässt sich festlegen, wo ein Element beginnt und wie viele Rasterfelder es einnimmt.

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:

Mögliche Angaben sind:

  • grid-column: 1 / 6;: Das Rasterelement erstreckt sich von der ersten bis zur 6. Rasterlinie.
  • grid-column: 1 / -1;: Die negative Liniennummer -1 bezeichnet die letzte Rasterlinie des expliziten Rasters. Automatisch erzeugte Spalten werden dabei nicht mitgezählt.
  • 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.


Festgelegte Rasterbereiche für header + article ansehen …
header,
footer {
  grid-column: 1 / -1;
}

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

Für den header und den footer legen wir mit grid-column fest, dass er in der ersten Spalte beginnen und dann am Ende der letzten Spalte ( also an der 6. Rasterlinie) enden soll.

Der article hat einen größeren Inhalt als die anderen Elemente. Deshalb erstreckt er sich von der 2. bis zur Rasterlinie horizontal. Vertikel beginnt er an der 2. Rasterlinie und überspannt 2 Felder (Grid-Items).

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!

Die anderen Rasterelemente werden wieder automatisch auf die Spalten verteilt. Dabei fällt auf, dass das letzte Rasterfeld der dritten Zeile freibleibt.

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.


Automatische Platzierung mit grid-auto-flow

Wenn man Rasterelemente fest positioniert oder Gridbereiche festlegt, können im Raster wie im oberen Beispiel Lücken entstehen. Diese können mit im Markup nachfolgenden Elementen gefüllt werden.

Der autoplacement-Algorithmus kann durch die grid-auto-flow-Eigenschaft gesteuert werden.

Ein gefülltes Raster mit grid-auto-flow: dense ansehen …
	body{
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(12em, 1fr));
	grid-auto-flow: dense;
	gap: 1em;
}

Durch das Schlüsselwort dense wird der Algorithmus so geändert, dass die vorher leeren Bereiche durch im Markup hinten stehende Elemente aufgefüllt werden.

Über ein Pseudoelement zeigt ein CSS-Zähler die eigentliche Position im Markup an.

Beachte, dass du das Schlüsselwort dense nur verwenden solltest, wenn es innerhalb des Grids keine fokussierbaren Elemente gibt, da eine Umordnung immer zu unlogischer Tab-Reihenfolge führt.

Anwendungsbeispiele

Ein solch flexibles Raster eignet sich vor allem für gleichförmige Elemente, bei denen unter Umständen die Reihenfolge verändert werden kann, ohne dass es zu Irritationen wie einem weit oben stehenden Seitenfooter kommt.

Responsives Grid

Die 30 Artikel der Erklärung der Menschenrechte sollen sich flexibel über den verfügbaren Viewport verteilen. Dabei soll keine Spaltenanzahl vorgegeben werden:

flexibles Grid Layout ohne media queries ansehen …
main {
  display: 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.

Bildergalerie

Der auto-placement-Algorithmus eignet sich besonders für Listen und Galerien, bei denen die genaue Reihenfolge unwichtig ist. In dieser Bildergalerie werden die unterschiedlich großen Bilder auf den verfügbaren Platz verteilt. Durch grid-auto-flow: dense; wird das Raster lückenlos gefüllt.

Bildergalerie ansehen …
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(133px, 1fr));
  gap: 10px;
  grid-auto-flow: dense;
}

.gallery figure.landscape {
  grid-column-end: span 2;
}

.gallery figure.panorama {
  grid-column-end: span 3;
}

In diesem Beispiel findet das entscheidende CSS nur im Elternelement statt:

  • display: grid; macht das div mit der id gallery zum Grid Container
  • grid-template-columns: repeat(auto-fill, minmax(133px, 1fr)); erzeugt Spalten, die mindestens 133px breit sind. Wenn die Gesamtbreite größer als ein Vielfaches der Mindestbreite ist, sodass normalerweise rechts ein Rand bliebe, verteilen die Spalten sich jedoch gleichmäßig über den verfügbaren Platz.
  • grid-auto-flow: dense; füllt das Raster lückenlos mit weiter hinten im Markup stehenden Elementen auf.


Neben dem Portrait-Modus, der eine Zelle umfasst, gibt es noch

  • ein landscape-Format, das sich durch grid-column-end: span 2; über zwei, sowie
  • ein panorama-Format, das sich über 3 Zellen erstreckt.
Bildergalerie ansehen …
.gallery figure {
  border: thin solid #ccc;
  position: relative;	
  margin: 0;
  counter-increment: posMarkup;	
}

.gallery figure img {
  display: block;
  object-fit: cover;
  width: 100%;
  height: 100%;
}

.gallery figure::after {
  content: counter(posMarkup, decimal);
  position: absolute;
  bottom: 0;
  color: red;
}

Die Bilder werden in ein figure-Element verpackt, das den browsereigenen Abstand durch margin: 0; normalisiert.

Die Bilder werden durch object-fit: cover; passend skaliert, ohne das Seitenverhältnis zu ändern.
Zur besseren Übersicht wie durch die Verwendung von dense kleinere Zellen in vorher entstandene Lücken platziert werden, wird in einem absolut positioniertem Pseudoelement die Reihenfolge jedes Bildes gekennzeichnet. Dabei werden zur Bildnummerierung CSS-Counter verwendet:

  • counter-increment erzeugt eine Variable, die dann im Pseudoelement ::after über content: counter(posMarkup, decimal); wieder ausgegeben wird.

Bilderwand aus Quadraten

Ist es möglich, eine Bilderwand mit Quadraten zu erzeugen, bei denen sich die Höhe an die flexible Breite anpasst?[5]

Das geht mit Grid layout und der aspect-ratio-Eigenschaft ganz einfach:

Bilderwand aus Quadraten - HTML ansehen …
<div class="square-container">
	<a id="kontakt" href="#">
		Kontakt
	</a>
	
	<a id="weltwunder" href="#">
		<img src="#" alt="Weltwunder" >
	</a>
       ...

Das CSS wird nur über den .square-container gesteuert:

Bilderwand aus Quadraten - CSS ansehen …
.square-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  grid-auto-rows: 1fr;
  grid-auto-flow: dense;
	max-width: 60em;
}

.square-container > * {
  background: rgb(0 0 0 / 0.1);
  border: thin solid transparent;
	aspect-ratio: 1 / 1;
}

.square-container img { 
  object-fit: cover; 
  width:100%; 
  height: 100%;  
	vertical-align: top; 
}

Damit die einzelnen Bilder, bzw. deren a-Elternelemente beim :hover oder dem Durchtabben mit der -Taste sichtbar werden, erhalten sie einen blauen Rand und eine verringerte Deckung:

Kennzeichnung des Fokus ansehen …
.square-container > a {
  border: 1px solid transparent;
  position: relative;
}

.square-container > *:focus,
.square-container > *:hover {
  border: 1px solid blue;
  opacity: .75;
}

Innerhalb der Bilderwand soll es zwei quadratische Links auf den Blog und die Kontaktseite geben:

(Fest) positionierte Links ansehen …
#blog,
#kontakt {
  background: url(handwriting.jpg);
  background-size:cover;
  display:flex; 
  align-items:center; 
  justify-content:center;
  font: 3rem bold; 
  text-decoration: none;
  color: red;
 }
 
#kontakt {
  grid-column: -2 / -1;  
 }

Während der erste Link aufgrund seiner Reihenfolge im HTML oben links im Raster positioniert ist, wird der Link mit der #kontakt mit grid-column oben rechts positioniert. Die negativen Werte zählen die Rasterlinien von rechts.

Masonry Tiles

Eine moderne Variante einer Bildergalerie ist das Masonry Layout, in dem sich Bilder innerhalb von flexiblen Spalten passend anordnen. Bis jetzt musste der Platzbedarf mit JavaScript verteilt werden - mit Grid Layout wird dies bald auch nur mit CSS möglich sein.[6]

Es gab verschiedene Entwürfe und bereits den Versuch einer Implementierung im FF79+. Diese wurden nun überarbeitet, funktionieren bisher (Stand: Oktober 2024) aber nur im Safari TP .

.grid-masonry {
  display: grid;
  gap: 1em;
  grid-template-columns: repeat(auto-fill, minmax(9em, 1fr));
  grid-template-rows: masonry;
}

Sobald die Spec festgelegt wurde und zwei Browser masonry unterstützen, werden wir diesen Abschnitt mit LiveBeispielen ausbauen.

--Matthias Scharwies (Diskussion) 05:39, 22. Okt. 2024 (CEST)

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.

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


Siehe auch

Ein 3x3 (oder 4x4) Raster mit Großansicht und mehreren thumbnails.

Weblinks

  1. W3C: Automatic Placement: the grid-auto-flow property
  2. MDN: Auto-placement in CSS Grid Layout
  3. css-tricks: The Difference Between Explicit and Implicit Grids von Manuel Matuzovic (10.08.2017)
  4. Rachel Andrews: Flexible Sized Grids with auto-fill and minmax
  5. SELF-Forum: flexible Bilderwand vom 23.02.2020
    2020 benötigte man dafür den padding-bottom height fix, um einem Element einen unteren Rand von 100% bei einer Höhe von 0 zu geben - der Prozentwert bezieht sich auf die Breite des Elements.
    Als Vorlage für die Quadrate diente ein Pseudoelement, das als erstes Grid-Item die Größe festlegte:
    .square-container {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
      grid-auto-rows: 1fr;
      grid-auto-flow: dense;
    }
    
    .square-container::before {
      content: '';
      height: 0;
      padding-bottom: 100%;
      grid-row: 1 / 1;
      grid-column: 1 / 1;
    }
    
    .square-container > *:first-child {
      grid-row: 1 / 1;
      grid-column: 1 / 1;
    }
    

    Heute verwendet man dafür aspect-ratio.
  6. MDN: Masonry layout