Aktualisiert 15. Juli 2026

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.

Die Rasteransicht von Scale Composer neben dem generierten CSS-Export: drei Breakpoint-Stufen als Custom Properties, plus die Container-, Raster- und Span-Klassen

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.

Weiterlesen

  • Was ist ein 12-Spalten-Raster?

    Ein 12-Spalten-Raster teilt die Seite in zwölf gleiche Spalten mit festen Stegen. Warum zwölf gewinnt: Hälften, Drittel, Viertel und Sechstel landen alle auf ganzen Spalten.

  • Spaltenspannen und Verschachtelung

    Wie grid column span funktioniert: die Span-Grammatik, Seiten-Muster wie 8+4 und 4+4+4, Spannen nach Inhalt und Ausrichtung wählen und Raster sauber verschachteln.