CSS/Tutorials/Grid/responsive Raster ohne Media Queries

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

Im Printdesign und auch bei „CSS-Frameworks“ wie bootstrap wird zuerst ein Gestaltungsraster erstellt, in dem die Rasterelemente dann fest platziert werden.
Im Webdesign mit seiner Unzahl von verschiedenen Viewportgrößen ist dies zwar auch möglich, oft aber gar nicht nötig.

In diesem Kapitel wird gezeigt, wie du mit wenigen CSS-Festlegungen Raster implizit erzeugst, deren Rasterelemente sich mit dem auto-placement-Algorithmus ohne den Einsatz von media queries responsiv anordnen.[1][2]

Grundlagen

Blockelemente wie Überschriften oder Absätze nehmen im Standardverhalten der Browser stets die verfügbare Breite ein. Mit der Einführung von CSS wurde es möglich, Positionierungen und Größenangaben auch außerhalb des Elementflusses festzulegen.

Dies ermöglichte einerseits ein pixelgenaues Layout, wurde andererseits bei einer Änderung des Viewports zum Bumerang, da sich Inhalte außerhalb des sichtbaren Bereichs oder unter anderen Elementen befanden oder durch overflow: hidden; abgeschnitten wurden. Media queries bieten hier eine Lösung, doch die immer wiederkehrende Frage nach den richtigen Breakpoints zeigt, dass aber auch dies nicht die einfachste Lösung ist.

Grid Layout beginnt wieder von vorne: Der verfügbare Raum wird aufgeteilt, weitere Inhalte werden innerhalb des Rasters in weiteren Reihen dargestellt und wandern so nach unten, wo man sie durch Scrollen erreichen kann.

Auch hier kann die Anzahl der Spalten mit media queries an die verfügbare Viewportbreite angepasst werden, wie schon in Kapitel 4 gezeigt wurde.

responsives Raster mit media queries
body{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 30em) { 
  body{
    grid-template-columns: repeat(3, 1fr);
}

@media (min-width: 50em) { 
  body{
    grid-template-columns: repeat(4, 1fr);
  }
}

Fazit:
Mit media queries kann man ein Raster mit einer festen Spaltenanzahl, deren Breite sich flexibel anpasst, erzeugen.
Könnte man dies so umdrehen, dass man als Ausgangspunkt die Breite der Spalten nimmt, die sich entsprechend der Viewportbreite unterschiedlich oft nebeneinander anordnen?
Ja, das geht!

Responsivität ohne Media queries

Im Folgenden soll gezeigt werden, wie Raster mit flexibler Spaltenanzahl angelegt werden, die sich auch ohne Media Queries responsiv an den Viewport anpassen.

auto-fill

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

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

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

grid-template-columns legt die Spalten eines Rasters fest. Als Wert dient die repeat()-Funktion, die nun über den ersten Parameter auto-fill so viele Spalten wie möglich erzeugt.
Der zweite Parameter gibt die Breite der Spalten (20em) vor.

Das article-Element soll, wenn der Platz ausreicht, breiter werden.

  • grid-column: 1 / -1; legt fest, dass der article an der ersten Gridlinie beginnt und an der letzten endet (negative Werte beginnen die Zählung rechts)
  • grid-row: span 2; das Element soll sich in der Höhe über 2 Reihen (Rasterfelder) erstrecken
Empfehlung: Öffne das Beispiel mit Rechtsklick in einem neuen Tab und verschiebe den Viewport. Der body hat eine rote Randlinie.
Was fällt dir auf?
Lösungshinweise anzeigenverbergen

Bei großen Viewports:

Das body-Element erhält mit max-width: 75em; eine Maximalbreite, die von den 3 je 20em breiten Rasterfeldern nicht völlig ausgefüllt wird.

Bei kleinen Viewports:

Das body-Element enthält 20em breite Raster, hat also dadurch eine feste Breite von 20em. Unterhalb dieser Viewportbreite ragt Inhalt aus dem sichtbaren Viewport; ein Scrollbalken wird angezeigt. Genau genommen bräuchte man hier eine media query, die das grid erst bei 40em Breite aktiviert:

@media (min-width: 40em) {
  display: grid;
  grid-template-columns: repeat(auto-fill, 20em);
}

minmax()

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:

ein gefülltes Raster ansehen …
@media (min-width: 40em) {
  body {
	display: grid;
        grid-template-columns: repeat(auto-fill, minmax(20em, 1fr));
  }
}

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

#news {
  grid-column: span 2;
}

In diesem Beispiel wurde die repeat()-Funktion verwendet, die nun über den ersten Parameter auto-fill so viele Spalten wie möglich erzeugt.
Der zweite Parameter besteht aus der minmax()-Funktion, die als Minimum einen Wert von 20em und, damit es z. B. bei 50em keine leeren Räume gibt, einen Maximalwert von 1 fr hat. Dann würden die 50em Breite in 2 Spalten a 25em Breite aufgeteilt.

Empfehlung: Öffne das Beispiel mit Rechtsklick in einem neuen Tab und beobachte.

Durch die Platzierung des article-Elements und der #news-Box über mehrere Spalten bleiben bei einem Dreispaltenlayout Rasterfelder frei.

Du könntest hier eines der weiter hinten gelegenen Elemente mittels einer Angabe von Grid-column, Grid-row, etc. nach vorne bringen. Dies wäre bei kleineren Viewports aber nicht nötig und würde deshalb kontraproduktiv sein. Überlass' dies dem autoplacement-Algorithmus!

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.

Folgende Angaben sind möglich:

  • row: (Standardwert) Die Spalten werden mit grid-template-columns explizit erzeugt; je nach Menge der Inhalte werden Zellen implizit erzeugt und in weiteren Reihen angefügt.
  • columns: Weitere Inhalte werden in implizit erzeugten Spalten angehängt.
  • dense: optionales Schlüsselwort, das kleinere Zellen in vorher entstandene Lücken platziert, sodass es zu einem gefüllten Raster kommt.
    Ohne dieses Schlüsselwort kommt der sparse-Modus zum Zug, der Elemente, wenn kein Platz vorhanden ist, in die nächste Reihe schiebt.
  • row dense:
  • column dense:
ein gefülltes Raster ansehen …
body{
  display: grid;
  grid-template-columns: auto auto auto;
  grid-auto-flow: dense;			
}

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

#news {
  grid-column: span 2;
}

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.

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?[3]

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.[4]

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)


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. SELF-Forum: flexible Bilderwand vom 23.02.2020
    2020 benötigte man dafür den padding-bottom height fix, mit dem einem Element ein unterer Rand von 100% bei einer Höhe von 0 gegeben wurde - 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.
  4. MDN: Masonry layout