Start / Web-Entwicklung / CSS Grid vs. Flexbox: wann nutzt man was?

CSS Grid vs. Flexbox: wann nutzt man was?

Die Frage kommt in praktisch jedem Einsteiger-Forum irgendwann auf, meist so formuliert: "Soll ich das mit Grid oder mit Flexbox bauen?" Die ehrliche Antwort ist unbefriedigender, als die Frage es verdient: Es kommt darauf an, ob dein Layout eine Achse hat oder zwei.

Das klingt nach einer Ausrede, ist aber tatsächlich die ganze Unterscheidung. Beide Systeme können Elemente nebeneinanderstellen, beide können umbrechen, beide kennen gap. Der Unterschied liegt darin, wer bestimmt, wie groß etwas wird: bei Flexbox eher der Inhalt selbst, bei Grid eher das Raster, das du vorher festlegst. Wer das einmal verinnerlicht hat, muss die Frage selten noch stellen. Dieser Artikel geht die beiden Systeme mit echtem Code durch, zeigt die neueren Werkzeuge wie Subgrid und Container Queries, die seit 2023 in allen großen Browsern laufen, und sammelt die Fehler, über die man in der Praxis tatsächlich stolpert.

Flexbox: eine Achse

Flexbox ordnet Elemente entlang einer Richtung an – entweder in einer Reihe oder in einer Spalte. Das macht es zum richtigen Werkzeug für alles, was sich wie eine Kette von Elementen verhält: eine Navigationsleiste, eine Button-Gruppe, eine Liste von Tags.

.nav {
  display: flex;
  align-items: center;
  gap: 12px;
}

Getestet im Browser: Mit gap statt Margin-Hacks bekommst du sauberen Abstand zwischen den Elementen, ohne dass der letzte Eintrag einen überflüssigen Rand mitschleppt – ein Problem, das früher mit :last-child-Selektoren umständlich gelöst werden musste.

Das Vokabular von Flexbox dreht sich um zwei Begriffe: die Hauptachse und die Querachse. flex-direction: row (der Standard) legt die Hauptachse horizontal, column legt sie vertikal. justify-content verteilt die Elemente entlang der Hauptachse, align-items richtet sie auf der Querachse aus. Die meisten Verwirrungen bei Einsteigern kommen daher, dass sich diese Zuordnung mit flex-direction: column umdreht: Plötzlich zentriert justify-content: center vertikal und nicht mehr horizontal.

Die eigentliche Stärke von Flexbox liegt in der Kurzschreibweise flex. Sie fasst drei Werte zusammen: wie stark ein Element wachsen darf (flex-grow), wie stark es schrumpfen darf (flex-shrink) und von welcher Ausgangsgröße es startet (flex-basis).

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.tags > a {
  flex: 0 0 auto;   /* so breit wie der Text, nie gestreckt */
}
.toolbar > .search {
  flex: 1 1 240px;  /* startet bei 240px, füllt den Rest */
}

Ein Detail, das man kennen sollte: Mit margin-left: auto auf einem einzelnen Flex-Element schiebst du es an das rechte Ende der Reihe. Das ist der klassische Weg, um in einer Kopfzeile das Logo links und den Login-Button rechts zu platzieren, ohne zusätzliche Wrapper oder justify-content: space-between, das bei drei oder mehr Elementen schnell unerwünschte Lücken erzeugt.

Grid: zwei Achsen gleichzeitig

Grid kontrolliert Zeilen und Spalten gleichzeitig – das richtige Werkzeug, sobald Elemente sowohl horizontal als auch vertikal aufeinander ausgerichtet sein müssen, etwa bei einem echten Seitenraster.

.layout {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
}
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
}

Der zweite Block ist kein Beiwerk, sondern der eigentliche Punkt: Ohne die Media Query bleibt das Raster auf einem Handy-Bildschirm dreispaltig und unlesbar. Grid macht das Layout mächtig, aber die Verantwortung fürs Responsive-Verhalten bleibt bei dir.

Für Kartenübersichten gibt es allerdings eine Schreibweise, die ganz ohne Media Query auskommt. Sie ist so verbreitet, dass sie fast schon ein eigenes Idiom ist:

.karten {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
}

Gelesen heißt das: Lege so viele Spalten an, wie hineinpassen, jede mindestens 240 Pixel breit, und verteile den übrigen Platz gleichmäßig. Auf einem breiten Monitor entstehen vier oder fünf Spalten, auf dem Handy eine. Der Unterschied zwischen auto-fill und auto-fit zeigt sich nur, wenn es weniger Elemente als mögliche Spalten gibt: auto-fill behält die leeren Spalten als Platzhalter, auto-fit lässt sie zusammenfallen, sodass die vorhandenen Karten sich über die ganze Breite strecken. Für eine Galerie mit wechselnder Anzahl von Bildern ist auto-fill meist die ruhigere Wahl, weil einzelne Karten dann nicht plötzlich riesig werden.

Die Denkrichtung: Inhalt nach außen oder Raster nach innen

Hinter der Achsen-Frage steckt ein zweiter, praktischerer Unterschied. Flexbox arbeitet vom Inhalt aus: Jedes Element bringt seine eigene Breite mit, und Flexbox verteilt, was übrig bleibt. Deshalb landen drei Buttons mit unterschiedlich langer Beschriftung in einer Flex-Reihe auch unterschiedlich breit, und das ist meistens genau richtig.

Grid arbeitet in die andere Richtung. Du beschreibst zuerst das Raster, also Spalten und Zeilen, und die Elemente werden in dieses Raster einsortiert. Ein Element in der zweiten Reihe weiß, wie breit das Element darüber ist, weil beide in derselben Spalte sitzen. Genau diese Eigenschaft fehlt Flexbox: Bei einer umbrechenden Flex-Reihe ist jede Zeile ein eigener kleiner Flex-Container, die Zeilen wissen nichts voneinander. Deshalb richten sich Kacheln in der letzten, unvollständigen Reihe bei Flexbox nicht an den Kacheln darüber aus, bei Grid schon.

Eine brauchbare Testfrage beim Bauen lautet deshalb: Soll die Größe eines Elements von seinem Inhalt abhängen oder von seiner Position im Layout? Hängt sie vom Inhalt ab, ist Flexbox meist das natürlichere Werkzeug.

grid-template-areas: ein Layout, das man lesen kann

Eine der unterschätzten Funktionen von Grid ist die Möglichkeit, das Seitenlayout als eine Art ASCII-Skizze direkt ins CSS zu schreiben. Statt Zeilen- und Spaltennummern zu zählen, benennst du Bereiche:

.seite {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-areas:
    "kopf  kopf"
    "menue inhalt"
    "fuss  fuss";
  gap: 24px;
}
.seite > header { grid-area: kopf; }
.seite > nav    { grid-area: menue; }
.seite > main   { grid-area: inhalt; }
.seite > footer { grid-area: fuss; }

@media (max-width: 700px) {
  .seite {
    grid-template-columns: 1fr;
    grid-template-areas: "kopf" "inhalt" "menue" "fuss";
  }
}

Der Vorteil zeigt sich beim Umbau für kleine Bildschirme: Du änderst nur die Skizze, nicht die einzelnen Elemente. Wer die Datei ein halbes Jahr später wieder öffnet, sieht das Layout auf einen Blick, ohne im Kopf nachzurechnen, was grid-column: 2 / 4 eigentlich bedeutet.

Ein Punkt verdient dabei eine Warnung: Grid (und auch order bei Flexbox) ändert nur die visuelle Reihenfolge. Screenreader und die Tab-Navigation mit der Tastatur folgen weiterhin der Reihenfolge im HTML. Im Beispiel oben landet das Menü mobil unter dem Inhalt, wer aber mit der Tab-Taste navigiert, springt trotzdem zuerst ins Menü. Das ist hier vertretbar, kann bei stärkeren Umsortierungen aber verwirrend werden. Die Faustregel: Die Quelltext-Reihenfolge sollte die sinnvolle Lesereihenfolge sein, CSS darf sie nur leicht umarrangieren.

Beide Systeme live nebeneinander

Der Unterschied wird am deutlichsten, wenn dieselben fünf Elemente einmal mit Flexbox und einmal mit Grid angeordnet werden – und der Platz knapp wird. Das hier ist kein Screenshot, sondern echtes CSS, das gerade in deinem Browser rechnet:

Flexbox · eine Achse

LogoPortfolioÜber michBlogKontakt
.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.nav > * { flex: 1 1 110px; }

Grid · zwei Achsen

LogoPortfolioÜber michBlogKontakt
.raster {
  display: grid;
  grid-template-columns:
    repeat(auto-fill, minmax(110px, 1fr));
  gap: 8px;
}

Zieh den Regler nach links: Sobald nicht mehr alle Elemente in eine Zeile passen, dehnt Flexbox die übrig gebliebenen Elemente der letzten Zeile auf die volle Breite – Grid hält dagegen die Spalten darüber und darunter exakt gleich breit.

Subgrid: wenn das Innenleben von Karten ausgerichtet sein soll

Ein Klassiker aus der Praxis: eine Reihe von Karten mit Bild, Überschrift, Text und Button. Die Überschriften sind unterschiedlich lang, manche brechen auf zwei Zeilen um. Das Ergebnis sind Buttons, die auf unterschiedlicher Höhe sitzen, obwohl die Karten selbst gleich hoch sind. Lange war die einzige Lösung, feste Höhen zu setzen oder mit JavaScript nachzumessen.

Subgrid löst das in CSS. Eine Karte kann die Zeilen ihres Eltern-Rasters übernehmen, statt ein eigenes zu bilden. Damit richten sich die Überschriften, Texte und Buttons aller Karten in einer Reihe aneinander aus:

.karten {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
}
.karte {
  display: grid;
  grid-row: span 4;             /* Bild, Titel, Text, Button */
  grid-template-rows: subgrid;  /* Zeilen vom Eltern-Grid erben */
  gap: 10px;
}

Firefox hatte Subgrid schon mit Version 71 im Dezember 2019, Safari kam mit Version 16 im September 2022 dazu, Chrome und Edge erst mit Version 117 im September 2023. Seit März 2026 gilt Subgrid im Baseline-System von web.dev als "Widely available", also seit mindestens 30 Monaten in allen großen Browsern. Für neue Projekte kann man es ohne Rückfallebene einsetzen. In Flexbox gibt es kein Gegenstück dazu, und das ist einer der seltenen Fälle, in denen die Wahl des Systems für ein einzelnes Bauteil wirklich zwingend ist.

Container Queries: Bauteile, die ihren eigenen Platz kennen

Media Queries fragen nach der Breite des Browserfensters. Für ein Seitenlayout ist das richtig, für einzelne Bauteile oft nicht: Dieselbe Karte kann im Hauptbereich 700 Pixel breit sein und in der Seitenleiste 280. Mit einer Media Query weiß die Karte davon nichts.

Container Queries drehen das um. Ein Element wird zum Container erklärt, und seine Kinder reagieren auf dessen Breite:

.karten-slot {
  container-type: inline-size;
}
.karte {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
@container (min-width: 420px) {
  .karte {
    flex-direction: row;   /* Bild links, Text rechts */
  }
}

Chrome unterstützt Größen-Container-Queries seit Version 105 (2022), Safari seit Version 16, Firefox seit Version 110 im Februar 2023. Im Beispiel stecken übrigens beide Systeme: Das Seitenraster bestimmt, wie breit der Slot ist, Flexbox ordnet innerhalb der Karte an, und die Container Query entscheidet, ob die Flex-Achse horizontal oder vertikal läuft. Das ist in modernem CSS der Normalfall.

Die Fehler, über die man tatsächlich stolpert

Überlaufende Inhalte in Flex- und Grid-Elementen. Flex-Elemente und Grid-Elemente haben standardmäßig min-width: auto, schrumpfen also nie unter die Breite ihres längsten, nicht umbrechbaren Inhalts. Eine lange URL oder ein Codeblock mit breiter Zeile sprengt dann das ganze Layout. Die Lösung ist fast immer min-width: 0 auf dem betroffenen Element, bei Grid alternativ minmax(0, 1fr) statt 1fr in der Spaltendefinition.

Prozentwerte plus gap. Wer in Flexbox mit flex-basis: 33.333% und zusätzlich gap: 20px arbeitet, bekommt keine drei Spalten, sondern zwei plus Umbruch, weil der Abstand zur Breite dazu gerechnet wird. Grid mit 1fr-Spalten zieht den Abstand dagegen vorher ab. Das ist einer der häufigsten Gründe, warum ein Flexbox-Raster "fast" funktioniert.

Grid für eindimensionale Listen. Eine Tag-Liste als Grid mit festen Spalten wirkt ordentlich, bis ein Tag deutlich länger ist als die anderen. Dann bricht es in seiner Zelle um, obwohl daneben Platz wäre. Inhalte mit sehr unterschiedlicher Länge fühlen sich in Flexbox wohler.

Alte Workarounds, die noch im Code stehen. Negative Margins am Container, um den Rand des letzten Elements auszugleichen, oder float-basierte Raster mit Clearfix: Solche Reste findet man in vielen älteren Stylesheets. Seit gap für Flexbox in allen großen Browsern läuft (Safari als letzter mit Version 14.1 im April 2021), sind sie überflüssig und lassen sich beim nächsten Umbau ersatzlos streichen.

Die Faustregel

Verhält sich dein Layout wie eine Kette (Navigation, Button-Reihe, Tag-Liste) → Flexbox. Verhält es sich wie ein Raster mit echten Zeilen und Spalten (Seitenlayout, Karten-Übersicht, Bildergalerie) → Grid. Und ja: die meisten realen Seiten benutzen beides gleichzeitig, ineinander verschachtelt – Grid für die große Struktur, Flexbox für die Details darin.

Wer das Ganze einmal in einem echten Projekt ausprobieren will, findet in einem Block-Theme für WordPress ein gutes Übungsfeld: Die Gruppen-Blöcke dort bieten die Varianten "Zeile", "Stapel" und "Raster" an, die im Hintergrund genau diese beiden Systeme erzeugen. Wie das im gespeicherten Code aussieht, zeigt unser Einstieg WordPress für Einsteiger.

Häufige Fragen

Kann man Grid und Flexbox auch kombinieren?

Ja, sogar sehr üblich: Grid für das große Seitenlayout, Flexbox innerhalb einzelner Grid-Zellen für die Anordnung von Karten-Inhalten, Buttons oder Navigationseinträgen.

Warum sprengt eine lange URL oder ein Codeblock mein Layout?

Weil Flex- und Grid-Elemente standardmäßig min-width: auto haben. Sie schrumpfen dadurch nie unter die Breite ihres längsten Inhalts, der sich nicht umbrechen lässt. Die Lösung ist fast immer min-width: 0 auf dem betroffenen Element. Bei Grid funktioniert alternativ minmax(0, 1fr) statt 1fr in der Spaltendefinition.

Was ist der Unterschied zwischen auto-fill und auto-fit?

Er zeigt sich nur, wenn es weniger Elemente als mögliche Spalten gibt. auto-fill behält die leeren Spalten als Platzhalter, die vorhandenen Karten bleiben so breit wie in einer vollen Reihe. auto-fit lässt die leeren Spalten zusammenfallen, und die Karten strecken sich über die ganze Breite. Für Galerien mit wechselnder Bildanzahl ist auto-fill meist die ruhigere Wahl.

Kann ich Subgrid und Container Queries ohne Fallback verwenden?

Für neue Projekte ja. Subgrid läuft seit September 2023 in allen großen Browsern, zuletzt kamen Chrome und Edge mit Version 117 dazu. Seit März 2026 führt web.dev es im Baseline-System als „Widely available“. Container Queries für Größen unterstützen Chrome ab Version 105, Safari ab 16 und Firefox ab 110. Wer sehr alte Browser bedienen muss, etwa in einem Firmennetz, sollte das vorher prüfen.

Ändert Grid die Reihenfolge für Tastatur und Screenreader?

Nein. grid-template-areas, order und ähnliche Eigenschaften verschieben Elemente nur optisch. Tab-Navigation und Screenreader folgen weiter der Reihenfolge im HTML. Leichte Umstellungen sind unproblematisch. Das HTML sollte aber in der Reihenfolge stehen, in der man die Seite sinnvoll liest.