Abschnitt 10 · Lektion 2
repeat(), minmax() und auto-fit
Drei Spalten zählst du noch gut von Hand ab, zwölf nicht mehr. Mit repeat() fällt das Abzählen weg. Und daraus wird ein Raster, das sich selbst an die Breite anpasst.
repeat
<p class="titel">vier Spalten von Hand</p>
<div class="raster hand">
<div class="zelle">1</div><div class="zelle">2</div>
<div class="zelle">3</div><div class="zelle">4</div>
</div>
<p class="titel">dieselben vier mit repeat</p>
<div class="raster kurz">
<div class="zelle">1</div><div class="zelle">2</div>
<div class="zelle">3</div><div class="zelle">4</div>
</div>
<p class="titel">repeat lässt sich mit festen Spuren mischen</p>
<div class="raster gemischt">
<div class="zelle">fest</div><div class="zelle">1</div>
<div class="zelle">2</div><div class="zelle">fest</div>
</div> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: system-ui, sans-serif;
}
.titel {
margin-bottom: 4px;
font-size: 14px;
color: #52525b;
}
.raster {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.zelle {
padding: 16px;
font-weight: 700;
color: #ffffff;
background-color: #2563eb;
}
.hand {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.kurz {
grid-template-columns: repeat(4, 1fr);
}
/* repeat ist keine eigene Zeile, sondern ein Stück
der Spurliste. Davor und dahinter darf stehen,
was du willst. */
.gemischt {
grid-template-columns: 120px repeat(2, 1fr) 120px;
} repeat(4, 1fr) bedeutet “viermal 1fr”. Mehr steckt nicht dahinter. Trotzdem ändert es, was sich bequem schreiben lässt, denn repeat(12, 1fr) ist ein Zwölf-Spalten-Raster in einer Zeile.
Im Reiter „Werte“ steht an den ersten beiden Rastern beide Male dieselbe Zeile, in der schmalen Spalte grid-template-columns: 82px 82px 82px 82px. Im Reiter „Regeln“ steht einmal 1fr 1fr 1fr 1fr und einmal repeat(4, 1fr). Der Unterschied liegt allein in der Datei.
repeat() muss auch nicht die ganze Spurliste ersetzen. Es kann ein Stück davon sein, und 120px repeat(2, 1fr) 120px ist völlig in Ordnung, mit festen Spalten außen und flexiblen innen. Wiederholen lässt sich auch ein Muster aus mehreren Spuren. repeat(3, 200px 1fr) legt sechs Spuren im Wechsel an.
minmax
<p class="titel">minmax(0, 1fr): die Spalten schrumpfen ohne Boden</p>
<div class="raster ohne">
<div class="karte">Ein Text, der schon zu eng steht.</div>
<div class="karte">Noch ein Text daneben.</div>
<div class="karte">Und ein dritter.</div>
<div class="karte">Und ein vierter.</div>
<div class="karte">Und ein fünfter.</div>
</div>
<p class="titel">minmax(200px, 1fr): unter 200px geht nichts</p>
<div class="raster mit">
<div class="karte">Ein Text, der jetzt Platz hat.</div>
<div class="karte">Noch ein Text daneben.</div>
<div class="karte">Und ein dritter.</div>
<div class="karte">Und ein vierter.</div>
<div class="karte">Und ein fünfter.</div>
</div> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: system-ui, sans-serif;
line-height: 1.5;
}
.titel {
margin-bottom: 4px;
font-size: 14px;
color: #52525b;
}
.raster {
display: grid;
gap: 12px;
margin-bottom: 24px;
}
.karte {
padding: 8px;
border-radius: 8px;
background-color: #ffffff;
border: 1px solid #d4d4d8;
}
/* Die 0 nimmt der Spur ihren Boden. Ein nacktes 1fr
hätte einen, es steht kurz für
minmax(auto, 1fr), und auto heißt "so schmal, wie
mein Inhalt gerade noch zulässt". Mit der 0 teilen
die fünf Spalten den Platz wirklich stur durch
fünf, egal wie wenig dabei herauskommt. */
.ohne {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
/* minmax setzt einen Boden. Passen fünf Spuren zu
200px nicht mehr nebeneinander, läuft das Raster
über, statt die Spalten weiter zu quetschen. */
.mit {
grid-template-columns: repeat(5, minmax(200px, 1fr));
} 1fr hat einen Boden, den man ihm nicht ansieht. Es steht kurz für minmax(auto, 1fr), und dieses auto heißt “so schmal, wie mein Inhalt gerade noch zulässt”. Fünf Spalten in einem schmalen Container schrumpfen also nicht bis auf null. Sie schrumpfen bis auf ihr längstes Wort. Zum Lesen hilft das wenig. Eine Spur, die genau ein Wort breit ist, bricht jedes Wort einzeln um, und irgendwann läuft das Raster trotzdem über.
minmax(200px, 1fr) gibt einer Spur eine Untergrenze und lässt sie darüber wachsen. Unter 200px geht sie nicht, darüber nimmt sie ihren Anteil am freien Platz. Damit bestimmst du den Boden und nicht mehr der Inhalt.
In der schmalen Spalte sieht man im Streifen, was das heißt. Am oberen Raster mit minmax(0, 1fr) sind es fünf Spuren zu je gut 63 Pixeln, am unteren mit minmax(200px, 1fr) fünfmal glatte 200px. Fünfmal 200 plus vier Lücken sind 1048 Pixel in einem Kasten, der 364 breit ist. Eine Untergrenze gibt nicht nach. Lieber läuft das Raster über, und deshalb gehört auto-fit daneben.
minmax(0, 1fr) im oberen Raster macht übrigens das Gegenteil. Es nimmt der Spur den Boden ganz weg, und sie darf schmaler werden als das, was in ihr steht. Ohne diese Angabe sähen sich die beiden Raster viel ähnlicher. Gebraucht wird das überall dort, wo ein einzelner zu langer Inhalt sonst ein ganzes Raster auseinanderdrückt.
Der erste Wert ist das Minimum, der zweite das Maximum. minmax(200px, 1fr) heißt “mindestens 200px, höchstens mein Anteil”. Andersherum geht es nicht. minmax(1fr, 200px) ist keine gültige Angabe, denn ein fr darf nur an der zweiten Stelle stehen. Der Browser wirft dann die ganze Deklaration weg, ohne etwas zu sagen, und dein Raster steht einspaltig da. Wie in 1.4 meldet sich der ungültige Wert nicht. Er hinterlässt nur eine Zeile, die es plötzlich nicht mehr gibt, und man sucht den Fehler woanders.
<div class="raster">
<div class="karte">Tipptrainer</div>
<div class="karte">Referenz</div>
<div class="karte">Newsletter</div>
</div> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: system-ui, sans-serif;
}
/* So nicht: das fr an erster Stelle. Gemeint waren drei
Spalten zwischen einem Anteil und 200px, aber ein fr
darf nur das Maximum sein. Die ganze Deklaration ist
damit ungültig, und das Raster hat eine einzige
Spalte. */
.raster {
display: grid;
grid-template-columns: repeat(3, minmax(1fr, 200px));
gap: 12px;
}
.karte {
padding: 16px;
border: 1px solid #d4d4d8;
border-radius: 8px;
} Im Beispiel stehen die drei Karten deshalb untereinander, jede so breit wie das Raster. Im Inspector steht am Raster bei grid-template-columns eine einzige Zahl, die volle Breite. Und im Reiter „Regeln“ fehlt die Zeile, die du geschrieben hast.
auto-fill und auto-fit
<p class="titel">auto-fill: die leeren Spuren bleiben stehen</p>
<div class="raster fill">
<div class="karte">Tipptrainer</div>
<div class="karte">Referenz</div>
</div>
<p class="titel">auto-fit: die leeren Spuren klappen zusammen</p>
<div class="raster fit">
<div class="karte">Tipptrainer</div>
<div class="karte">Referenz</div>
</div>
<p class="hinweis">
Mit vier oder mehr Karten sehen beide gleich aus. Der Unterschied
zeigt sich nur, wenn weniger Karten da sind als Spuren hineinpassen.
</p> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: system-ui, sans-serif;
line-height: 1.5;
}
.titel {
margin-bottom: 4px;
font-size: 14px;
color: #52525b;
}
.raster {
display: grid;
gap: 16px;
margin-bottom: 24px;
}
.karte {
padding: 24px;
border-radius: 12px;
font-weight: 700;
color: #ffffff;
background-color: #2563eb;
}
/* Beide legen so viele Spuren an, wie hineinpassen.
auto-fill lässt die unbenutzten stehen, deshalb
bleiben die zwei Karten schmal am linken Rand. */
.fill {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
/* auto-fit klappt die unbenutzten auf Breite null
zusammen. Die zwei Karten teilen sich damit die
ganze Zeile. */
.fit {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.hinweis {
max-width: 56ch;
color: #52525b;
} Statt einer Zahl darf in repeat() auch ein Schlüsselwort stehen. Es gibt zwei, und beide legen so viele Spuren an, wie in den Container hineinpassen.
auto-filllässt die Spuren stehen, auch wenn nichts darin liegt.auto-fitklappt die leeren auf Breite null zusammen, und die vorhandenen Elemente füllen den ganzen Platz.
Den Unterschied siehst du nur, wenn weniger Elemente da sind, als Spuren hineinpassen. Bei zwölf Karten in einem Raster für vier verhalten sich beide gleich, und deshalb hält man sie so lange für dasselbe. Platz braucht es dafür auch. In der schmalen Spalte ist die Seite zu eng für mehrere Spuren, und in beiden Rastern steht grid-template-columns: 364px. Eine einzige Spur. Im Vollbild steht die Seite auf den 900 Pixeln, für die das Beispiel gebaut ist.
Dann lohnt der Blick in den Streifen mehr als der aufs Bild. Beim auto-fill-Raster steht dort grid-template-columns: 209px 209px 209px 209px, beim auto-fit-Raster 434px 434px 0px 0px. Vier Spuren gegen vier Spuren. auto-fit wirft die leeren also gar nicht weg. Es drückt sie auf null zusammen, und die beiden vollen nehmen sich den Platz. Auf dem Bild siehst du zweimal zwei Karten, einmal schmal und einmal breit. Im Streifen siehst du, warum.
Zusammen ergibt das eine Zeile, die ein ganzes Kartenraster trägt, repeat(auto-fit, minmax(…, 1fr)). An die Stelle der Punkte kommt die Breite, unter die eine Karte nicht schrumpfen soll. Der Browser legt dann so viele Spalten an, wie mit dieser Mindestbreite hineinpassen, und lässt sie den Platz gleichmäßig füllen. Auf einem breiten Bildschirm sind das mehrere Spalten, auf dem Handy eine. Eine Media Query brauchst du dafür nicht.
Bequemer ist das sowieso, und es ist auch das bessere Ergebnis. Eine Media Query kennt nur die Breite des Fensters. Das Raster hier kennt die Breite seines Containers, und die kann eine ganz andere sein, wenn es in einer Seitenspalte steckt.
In der Aufgabe steht das Projektraster noch mit drei fest abgezählten Spalten da.
Zum Mitnehmen
repeat(auto-fit, minmax(…, 1fr)) legt so viele Spalten an, wie hineinpassen, und klappt leere zusammen. Die Untergrenze bleibt eine Untergrenze, auch bei einer einzigen Spalte.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
Was in dieser Lektion steckt
-
Artikel mit 4 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.