Das Raster in reinem CSS aufbauen
Eine Seite, die auf einem Framework aus der 2013er-Ära gebaut war, kündigte
ihr Layout in jedem Tag an: class="col-xs-12 col-sm-6 col-md-4" auf Karte
um Karte, eine Klasse pro Element pro Breakpoint, mit einem
Framework-Stylesheet im Schlepptau, damit die Klassen überhaupt etwas
bedeuten. Das moderne Äquivalent dieses ganzen Apparats sind rund zwanzig
Zeilen CSS, die du in einem Rutsch lesen kannst.
Ein CSS Raster-System in modernem CSS ist ein Satz von Custom Properties, die die Entscheidungen pro Breakpoint tragen — Spaltenanzahl, Steg, Rand —, innerhalb von Media Queries neu deklariert, plus drei Klassen, die sie konsumieren: ein Container, der die Seite begrenzt und zentriert, ein Raster, das die Spalten anlegt, und Span-Klassen, mit denen Elemente Spaltenbreiten beanspruchen. Keine Framework-Abhängigkeit, kein Build-Schritt; die eigene Layout-Engine des Browsers erledigt die Arbeit, die das Framework früher simulieren musste.
Dieser Artikel geht diesen Code Zeile für Zeile durch: die Variablen-Schicht,
die drei Klassen, den minmax(0, 1fr)-Fallstrick und den einzeiligen
Clamping-Trick, der den Klassen-Wildwuchs pro Breakpoint ersetzt. Es ist die
Implementierungs-Hälfte des Themas Raster-Layout — was
die Spalten, Stege und Breakpoints sein sollen, ist die Aufgabe des
restlichen Clusters.
Wie ist das Raster zwischen Variablen und Klassen aufgeteilt?
Die Architektur hat genau zwei Schichten, und die Aufteilung ist der springende Punkt.
Die Variablen sind die Design-Entscheidungen. --grid-cols,
--grid-gutter und --grid-margin halten die Werte jeweils einer Stufe:
4 / 16px / 16px auf Telefonen, neu deklariert zu 8 / 24px / 29px ab 768px und
12 / 24px / 66px ab 1200px. --container hält die
globale Obergrenze.
Diese paar Zahlen pro Stufe
sind die gesamte Layout-Politik — alles, was ein Team tatsächlich entscheidet,
wenn es „das Raster“ festlegt.
Die Klassen sind die Mechanik. .grid-container, .grid und die
.col-N-Spans enthalten keine eigene Zahl; sie lesen nur die Variablen. Die
Mechanik wird einmal geschrieben und danach selten angefasst — ein Redesign
oder ein neuer Breakpoint ändert nur die :root-Blöcke.
Wenn du mit design tokens arbeitest, ist die Parallele exakt: Die Variablen sind Layout-Tokens zur Laufzeit. Dieselben Spalten-/Steg-/Rand-Werte, die im Layout-Abschnitt einer Token-Datei leben, werden hier zu Custom Properties, und die Klassen spielen die Rolle, die Komponenten überall sonst in einem Token-System spielen — Konsumenten von Entscheidungen, nie deren Besitzer.
Wie sieht das vollständige Raster-CSS aus?
So sieht der CSS-Export von Scale Composer für sein Standard-Raster aus, annotiert:
/* Raster-Tokens
* Globale max-width: 1200px
* Mobil: ≥0px → 4 Spalten · Steg 16px · Rand 16px
* Tablet: ≥768px → 8 Spalten · Steg 24px · Rand 29px
* Desktop: ≥1200px → 12 Spalten · Steg 24px · Rand 66px
*/
:root { /* die Mobil-Stufe ist der Standard */
--container: 1200px;
--grid-cols: 4;
--grid-gutter: 16px;
--grid-margin: 16px;
}
@media (min-width: 768px) { /* Tablet deklariert die Entscheidungen neu */
:root {
--grid-cols: 8;
--grid-gutter: 24px;
--grid-margin: 29px;
}
}
@media (min-width: 1200px) { /* Desktop deklariert sie erneut */
:root {
--grid-cols: 12;
--grid-gutter: 24px;
--grid-margin: 66px;
}
}
.grid-container { /* begrenzt und zentriert die Seite */
max-width: var(--container);
margin-inline: auto;
padding-inline: var(--grid-margin);
}
.grid { /* legt die Spalten an */
display: grid;
grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr));
gap: var(--grid-gutter);
}
/* Spans — auf die Spaltenanzahl der aktuellen Stufe geklammert */
.col-1 { grid-column: span min(1, var(--grid-cols)); }
.col-2 { grid-column: span min(2, var(--grid-cols)); }
/* … .col-3 bis .col-11 folgen demselben Muster … */
.col-12 { grid-column: span min(12, var(--grid-cols)); }
Die drei Klassen teilen sich die Arbeit sauber auf. .grid-container besitzt
den Seitenrahmen: max-width begrenzt ihn, margin-inline: auto zentriert
ihn, padding-inline hält den Inhalt um den Rand der Stufe von der
Viewport-Kante fern. .grid besitzt die Spalten:
repeat(var(--grid-cols), minmax(0, 1fr)) erzeugt gleiche fluide Tracks und
gap setzt den Steg zwischen sie — die
grundlegende Mechanik von CSS Grid
erledigt die gesamte Rechnerei. Die .col-N-Klassen besitzen nichts außer
einem Anspruch: N Spalten überspannen,
was auch immer eine Spalte gerade ist.
Öffne diesen Export, annotiert, in Scale Composer — die Rasteransicht erzeugt den Block oben aus ihren Einstellungen pro Breakpoint, wobei jeder Steg und Rand an die gemeinsame Abstands-Skala eingerastet ist.

Warum minmax(0, 1fr) statt einfachem 1fr?
Weil 1fr allein eine Untergrenze hat. Es ist die Kurzform für
minmax(auto, 1fr), und auto bedeutet „mindestens die Mindestgröße dieses
Inhalts“. Setze eine lange, ununterbrochene URL, eine breite Tabelle oder
einen <pre>-Block in eine Spalte eines repeat(12, 1fr)-Rasters, und diese
Spalte wächst still über ihren gerechten Anteil hinaus; die anderen elf
schrumpfen, um Platz zu schaffen, und das Versprechen gleicher Spalten bricht
in genau der Zeile, die zufällig den breitesten Inhalt enthält. Es ist eine
der am häufigsten angetroffenen Debugging-Überraschungen in Grid, gerade weil
nichts einen Fehler wirft — das Layout ist einfach falsch, und nur in Zeilen
mit unhandlichem Inhalt.
minmax(0, 1fr) entfernt die Untergrenze. Jeder Track ist immer genau ein
Bruchteil des freien Raums; Inhalt, der breiter als seine Spalte ist, läuft
aus der Spalte heraus — sichtbar, behebbar — statt das ganze Raster um sich
zu biegen. Ehrliche Tracks, ehrlicher Überlauf.
Wie überstehen Spans kleinere Breakpoints?
Diese Zeile ist der Punkt, an dem die Ära des Klassen-Wildwuchses wirklich endet:
.col-8 { grid-column: span min(8, var(--grid-cols)); }
Ein naives span 8 verhält sich auf Telefonen daneben: Die Mobil-Stufe hat
vier explizite Spalten, und Grid honoriert einen zu großen Span, indem es
implizite Tracks erzeugt — aus dem Vier-Spalten-Raster wird still ein
Acht-Spalten-Raster, und alles andere darauf schrumpft und verrutscht. Den
Span in min(N, var(--grid-cols)) einzupacken wertet den Anspruch stattdessen
pro Stufe neu aus: Ein .col-8-Element nimmt acht von zwölf Spalten auf dem
Desktop, alle acht auf dem Tablet und klammert sich auf einem Telefon auf alle
vier — volle Breite, und genau das ist Stapeln. Keine zweite Klasse, keine
zusätzliche Media Query.
Die Framework-Ära löste dasselbe Problem mit Klassen pro Stufe
(col-md-8 col-sm-4): eine Entscheidung pro Element pro Breakpoint, im Markup
kodiert. Das Clamp ersetzt diese Taxonomie durch einen Standard — und wo der
Standard-Umbruch nicht das Design ist, das du willst, ist ein innerhalb einer
Media Query neu deklarierter Span jetzt die Ausnahme statt das System.
Wie sieht eine darauf gebaute Seite aus?
Eine Seite mit drei Abschnitten — Hero, Artikel mit Seitenleiste, Kartenreihe — ist Markup plus Ansprüche:
<body class="grid-container">
<header class="grid">
<h1 class="col-12">Hero — full width at every tier</h1>
</header>
<main class="grid">
<article class="col-8">Article body</article>
<aside class="col-4">Sidebar</aside>
</main>
<section class="grid">
<div class="col-4">Card</div>
<div class="col-4">Card</div>
<div class="col-4">Card</div>
</section>
</body>
Auf der Desktop-Stufe gehen die Zahlen so auf: Der Container begrenzt bei 1200px, die Ränder nehmen 2 × 66px, die elf Stege nehmen 11 × 24px = 264px, und jede Spalte bekommt (1200 − 132 − 264) ÷ 12 = 67px. Der Artikel überspannt 8 × 67 + 7 × 24 = 704px, die Seitenleiste und jede Karte 340px. Auf einem 375px-Telefon klammert sich jeder dieser Spans auf vier Spalten, und die Seite wird zu einem sauberen einspaltigen Stapel — es wurde nichts Zusätzliches geschrieben, damit das passiert.
Was kann ein zwanzigzeiliges Raster nicht?
Es positioniert Boxen auf einem gemeinsamen Satz von Spalten, und mehr tut es
nicht. Es hat keine Antwort darauf, die Innenleben benachbarter Karten
aneinander auszurichten (das ist die Aufgabe von subgrid), kein
Masonry-Packing, keine benannten Bereiche, keine Auto-Placement-Cleverness.
Nichts davon ist ein Mangel des Musters; es markiert den Punkt, an dem du
aufhörst, das System zu benutzen, und anfängst, CSS Grid direkt zu benutzen —
grid-template-areas oder subgrid auf der konkreten Komponente, die es
braucht. Das System deckt die Seite ab; Grid selbst deckt die Sonderfälle ab.
Exportiere ein Raster mit deinen eigenen Zahlen
Der schnellste Weg, dieses Muster zu verinnerlichen, ist, es aus Entscheidungen zu generieren, die du selbst getroffen hast. Lege die Spalten, Stege und Ränder pro Breakpoint in der Rasteransicht fest — jedes Maß schreitet durch dieselbe Abstands-Skala, aus der sich der Rest des Systems bedient — und lies dann das Stylesheet, das dabei herausfällt: exportiere das Raster-CSS mit deinen eigenen Breakpoint-Werten in Scale Composer.