- 1 Grundlagen
- 2 Flexbox
- 3 Raster und Unterraster
- 4 Containerabfragen
- 5 Native Overlays, Ankerpositionierung und Stapelkontexte
- 6 Überlauf-Tracking und Layoutstabilität
- 7 Viewport-Mechanik und Track-Verteilung
- 8 Rasterspalten (auch „Masonry“ genannt)
1 Education Fundamentals
Verwenden Sie nach Möglichkeit die Layout-Engine des Browsers, um die Leistung zu verbessern. Verwenden Sie intrinsische Größen, logische Eigenschaften und aspect-ratio, bevor Sie auf hartcodierte Dimensionen oder komplizierte Medienabfragen zurückgreifen.
1.1 Welcher Layoutmodus soll verwendet werden?
Gehen Sie den Entscheidungsbaum von oben nach unten durch und halten Sie beim ersten Treffer an. Layouts können ineinander verschachtelt werden. Jede Entscheidung basiert auf dem Anwendungsfall für den jeweiligen Container.
- Handelt es sich um eine einfache Zeile ODER Spalte mit Elementen? Verwenden Sie Flexbox – 1D, inhaltsorientiert, Inhalte werden entlang einer einzelnen Achse verteilt.
- Muss ein verschachteltes Element an den Spuren des übergeordneten Rasters ausgerichtet werden? Verwenden Sie subgrid – 2D, beziehungsorientiert, übernimmt übergeordnete Tracks, sodass Enkelkinder sich an Geschwistern ausrichten können.
- Ist es eine komplexe Seiten- oder Komponentenstruktur mit Zeilen UND Spalten? Verwenden Sie grid – 2D, Layout-First, Sie definieren das Skelett und der Inhalt füllt es.
- Besteht der Inhalt aus einem langen Fließtext, der in ausgewogene Spalten aufgeteilt werden sollte? Verwenden Sie mehrere Spalten – 1D-Fluss, Zeitungsstil.
- Müssen Artikel unterschiedlicher Höhe dicht gepackt werden? Verwenden Sie heute grid mit
grid-auto-flow: dense. Greifen Sie erst dann auf natives Masonry (auch „Grid Lanes“ genannt) zurück, wenn es in Ihrem Baseline-Ziel verfügbar ist (siehe § 8). - Muss ein Element über der Seite schweben und räumlich an einen Trigger gebunden bleiben, auch über DOM-Grenzen oder Stapelkontexte hinweg? Verwenden Sie die Ankerpositionierung –
anchor-namefür den Trigger,position-anchorfür das Overlay (siehe § 5).
1.2 Arbeitsprinzipien
- Verwenden Sie logische Eigenschaften (
inline-size,block-size,margin-inline,padding-block,inset-inline-start) für Layoutdimensionen und Abstände. Weitere Informationen finden Sie unter CSS: Moderne Architektur. - Wenden Sie das mentale Modell „Inhalt zuerst“ oder „Layout zuerst“ an: Flexbox, wenn die Elemente den Fluss vorgeben, Grid, wenn Sie zuerst das Skelett definieren.
- Verwenden Sie die
place-*-Kurzschreibweisen (place-content,place-items,place-self), um die Ausrichtung auf beiden Achsen in einer Deklaration festzulegen. - Verwenden Sie die intrinsische Größenanpassung (
min-content,max-content,fit-content()) und flexible Tracks (fr,minmax()) anstelle von festenwidth/height-Werten. Das bedeutet weniger Medienabfragen und robustere Layouts. - Verwenden Sie
overflow: hiddenNICHT, um Layoutprobleme zu verbergen. Beheben Sie sie stattdessen an der Quelle. Beispielsweise verwenden bestimmte ersetzte Elemente wie<canvas>,<img>,<svg>,<video>und<iframe>standardmäßigdisplay: inline, was in bestimmten Layouts zu einer Lücke führen kann. Anstatt die Lücke mitoverflowzu entfernen, entfernen Sie sie, indem Sie einen Block-Display-Outside-Wert anwenden (z.B.display: block,grid,flex). - Verwende
aspect-ratio, um Platz für Medien zu reservieren und Layout Shifts zu verhindern, bevor Assets geladen werden.
.sidebar { inline-size: max-content; } /* Size to longest unbreakable token. */
.main-content { inline-size: fit-content; } /* Grow to available space, no further. */
.media { aspect-ratio: 16 / 9; inline-size: 100%; block-size: auto; }
body.centered { display: grid; place-content: center; min-block-size: 100dvb; }
Informationen zu
calc-size()und zur intrinsischen Größenanpassung unter Berücksichtigung von Einschränkungen finden Sie unter Mit intrinsischen Größen berechnen.
2 Flexbox
Eindimensionales Layout: Die Elemente werden entlang einer einzelnen Hauptachse angeordnet und an der Querachse ausgerichtet. Verwenden Sie es für Navigationsleisten, Symbolleisten, Elementzeilen und alle einzeiligen oder einspaltigen Verteilungen.
Das sollten Sie tun:
- Erstellen Sie einen Kontext mit
display: flexund legen Sie die Hauptachse mitflex-directionfest (rowist der Standardwert). - Verwenden Sie
flex-wrap: wrap, wenn ein Überlauf möglich ist.nowrapohneoverflow: auto/hiddenwird auf schmalen Darstellungsbereichen überlaufen. - Layer
flex-wrap: balancenachflex-wrap: wrapin umgebrochenen Zeilen kompakter Elemente (z. B. Tag-Clouds, Filter-Pills, Schaltflächengruppen oder Navigationslinks), um Elemente gleichmäßig auf Zeilen zu verteilen und ein einzelnes verwaistes Element in der letzten Zeile zu verhindern. Browser ohne Unterstützung greifen aufwrapzurück. - Verwenden Sie für Elemente die Kurzschreibweise
<grow> <shrink> <basis>vonflex(z.B.flex: 1 1 250px), anstattflex-grow/flex-shrink/flex-basiseinzeln festzulegen. - Verwenden Sie
gap(oder die Langformrow-gap/column-gap) für den Abstand zwischen Elementen anstelle von untergeordneten Rändern. - Stellen Sie der Positionsausrichtung
safevoran (z.B.align-items: safe center), damit fokussierbare Inhalte nicht abgeschnitten werden, wenn der Container schmaler als sein Inhalt ist. - Mit
margin-inline-start: auto(odermargin-block-start: auto) können Sie ein einzelnes Element an das Ende der Hauptachse verschieben. Das ist die Standardmethode. - Mit
align-selfkönnen Sie die Querachsenausrichtung für einzelne Elemente überschreiben. - Verwenden Sie
align-items, um alle Elemente auf der Querachse zu zentrieren. Verwenden Siemargin: autofür ein einzelnes Element, um es unabhängig auf beiden Achsen zu zentrieren. Verwenden Siealign-contentnur, wenn der Container umbricht und zusätzlichen Platz zwischen den Zeilen hat. - Legen Sie
min-inline-size: 0(odermin-width: 0) für Flex-Elemente fest, die lange, nicht umbrechbare Inhalte (URLs, Code, lange Strings) enthalten. Flex-Elemente werden standardmäßig nicht unter ihre Inhaltsgröße verkleinert, was zu einem Überlauf führt.
Nicht empfohlen:
- Verwenden Sie
justify-selfnicht für Flex-Elemente – es funktioniert nur bei Grid-, Block- und absolut positionierten Layouts. Verwenden Sie stattdessen automatische Ränder. - Verwenden Sie nicht
orderoderflex-direction: *-reverse, um interaktive Inhalte neu anzuordnen. Sie ändern nur die visuelle Reihenfolge. Die DOM-Reihenfolge bestimmt weiterhin den sequenziellen Fokus, sodass der Tab-Ablauf auf der Tastatur nicht mit dem übereinstimmt, was der Nutzer sieht. - Verwechseln Sie
space-around(halber Abstand an den Enden) nicht mitspace-evenly(gleiche Abstände davor, dazwischen und danach). - Vergessen Sie nicht, die Achsen umzukehren: Wenn
flex-direction: column, wirdjustify-contentan der Blockachse undalign-itemsan der Inline-Achse ausgerichtet – das Gegenteil der Standardeinstellung. - Legen Sie die Größe des Containers und seiner untergeordneten Elemente nicht so fest, dass sie sich gegenseitig ausfüllen. Das ist eine häufige Ursache für Überlauf und unerwartete Ergebnisse. Geben Sie einer Seite eine feste Größe.
- Legen Sie nicht sowohl
flex-basisals auchwidth/inline-sizefür dasselbe Element fest.flex-basishat in einem Flex-Kontext Vorrang undwidthwird ignoriert. Verwenden Sieflex-basis(oder die Kurzschreibweiseflex) als einzige verlässliche Quelle für die Größenanpassung von Flex-Elementen.
.card-grid { display: flex; flex-flow: row wrap; gap: 1rem; }
.card-item { flex: 1 1 250px; } /* grow, shrink, basis */
.card-item-action { margin-inline-start: auto; } /* Push to main-axis end. */
.toolbar { display: flex; align-items: safe center; }
.tag-list { display: flex; flex-wrap: wrap; flex-wrap: balance; gap: 0.5rem; }
3 Raster und Unterraster
Zweidimensionales Layout: Zeilen UND Spalten explizit definieren oder von der Engine ableiten lassen. Mit Subgrid kann ein verschachteltes Raster die Tracks des übergeordneten Rasters übernehmen, sodass Enkelkinder an Geschwistern ausgerichtet werden.
Rastermerkmale auswählen:
- Wissen Sie genau, wie viele Spalten Sie benötigen?
- Ja – explizite Tracks verwenden (
grid-template-columns: 200px 1fr,repeat(3, 1fr)usw.) - Benötigen verschiedene Spalten unterschiedliche Größen (Seitenleiste + Hauptbereich, Header, der sich über alle Spalten erstreckt)? → Verwenden Sie
grid-template-areasfür benannte, lesbare Regionen. - Sind alle Spalten einheitlich oder nur nach Zeilennummer positioniert? →
repeat(N, ...)oder benannte Linien verwenden - Nein (responsiv, unbekannte Anzahl von Elementen) –
repeat(auto-fit, minmax(min, 1fr))verwenden - Sollen Elemente in der letzten Zeile gestreckt werden, um den verbleibenden Platz auszufüllen? →
auto-fit - Sollen leere Tracks in der letzten Zeile ihre Mindestgröße beibehalten (Spalten-Ghost-Slots beibehalten)? →
auto-fill
- Ja – explizite Tracks verwenden (
- Müssen Sie ein Element an einer bestimmten Stelle platzieren?
- Ja – Verwenden Sie
grid-column: <start> / <end>odergrid-area: <name>. - Nein (nur über mehrere Tracks, die Position im Ablauf ist egal) –
grid-column: span <n>verwenden
- Ja – Verwenden Sie
- Müssen untergeordnete Elemente die Spurgrößen des übergeordneten Rasters übernehmen (Ausrichtung mit unregelmäßigen Kanten über gleichgeordnete Elemente hinweg)?
- Ja – Subgrid auf der betroffenen Achse verwenden
- Ist die Anzahl der untergeordneten Elemente pro Zelle variabel? → Subgrid nur eine Achse; für die andere
grid-auto-rows/grid-auto-columnsverwenden - Ist die Anzahl der Kinder festgelegt? → Subgrid auf beiden Achsen ist in Ordnung
- Nein – Standardraster, kein Unterraster erforderlich
Das sollten Sie tun:
- Kontext mit
display: gridherstellen. - Verwenden Sie
grid-template-areasfür komplexe Layouts auf Seitenebene. Die Bereichsnamen sind selbsterklärend und die Deklaration kann in Zeilen und Spalten ausgerichtet werden, um die Lesbarkeit zu verbessern. - Verwenden Sie
repeat(auto-fit, minmax(200px, 1fr))für responsive Kartenraster, bei denen gefüllte Tracks gestreckt werden, um die Zeile zu füllen, oderauto-fill, um leere wiederholte Tracks in ihrer Mindestgröße beizubehalten. - Verwenden Sie
frfür die proportionale Trackverteilung undminmax(min, max)für flexible, aber begrenzte Tracks. - Positionieren Sie Elemente mit
grid-column: span <n>, um die Größe über Tracks hinweg festzulegen, mitgrid-column: <start> / <end>, um sie an bestimmten Linien zu platzieren, oder mitgrid-area: <name>für benannte Bereiche. - Verwenden Sie ein Subgrid (
grid-template-columns: subgridodergrid-template-rows: subgrid), um das Problem der ungleichmäßigen Kanten in Kartenlisten zu lösen. Interne Elemente wie Titel, Metadaten und CTAs werden dann über gleichrangige Elemente hinweg ausgerichtet. - Kombinieren Sie eine Subgrid-Deklaration mit einer vorherigen expliziten
grid-template-rows/-columns-Deklaration als Fallback für ältere Browser.
Nicht empfohlen:
- Die Größe des
auto-fit/auto-fill-Tracks wird nicht aus dem Elementinhalt, sondern aus dem Größenargumentrepeat()abgeleitet. - Verwenden Sie
grid-auto-flow: densenicht für interaktive Inhalte. Elemente werden effizient gepackt, aber visuell neu angeordnet, wodurch der Tab-Ablauf der DOM-Reihenfolge unterbrochen wird. - Wenden Sie das Subgrid nicht auf beide Achsen an, wenn die Anzahl der untergeordneten Elemente variabel ist. Zusätzliche Elemente landen im letzten Track. Verwenden Sie stattdessen
grid-auto-rows/grid-auto-columnsfür die implizite Achse. - Verwechseln Sie
justify-items/align-items(richtet den Elementinhalt innerhalb des Tracks aus) nicht mitjustify-content/align-content(richtet die Grid-Tracks innerhalb des Containers aus). Wenn Sie den falschen verwenden, hat das keine Auswirkungen. - Verwenden Sie
repeat(auto-fit/auto-fill, ...)nicht ohne eine definierteinline-sizefür den Container. Innerhalb vondisplay: inline-gridoder einem Flex-Element ohne Größe hat der Container keine Breite, die aufgeteilt werden kann, was die Anzahl der Tracks unvorhersehbar macht.
3.1 Codebeispiel: Raster und Unterraster
Seiten-Shell: <main class="page-layout"> enthält <header>, <aside>, ein <section class="card-grid"> mit <div class="card"> untergeordneten Elementen und <footer>.
/* Align grid-template-areas in rows and columns for readability. */
.page-layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
gap: 1.5rem;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
footer { grid-area: footer; }
.card-grid {
grid-area: main;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-rows: auto 1fr; /* title block, body block */
gap: 1rem;
}
.card {
grid-row: span 2;
display: grid;
/* Same-cascade fallback: ignored when subgrid is supported. */
grid-template-rows: auto 1fr;
grid-template-rows: subgrid;
}
4 Containerabfragen
Fragen Sie die Größe (oder den berechneten Stil) eines übergeordneten Containers anstelle des Darstellungsbereichs ab. Mentales Modell: Containerabfragen = Komponentenkontext; Medienabfragen = globales Seitenlayout und Nutzereinstellungen (prefers-color-scheme, prefers-reduced-motion).
Das sollten Sie tun:
- Richten Sie mit
container-type: inline-size(nur Abfragen zur Breite) odercontainer-type: size(beide Achsen) einen Containerkontext für einen Wrapper ein, bevor seine untergeordneten Elemente abgefragt werden können. - Benennen Sie Container mit
container-name(oder der Kurzformcontainer:container: card / inline-size), wenn verschachtelte Kontexte kollidieren könnten. - Containerabfrageeinheiten bei der Berechnung von flüssigem Typ und Abstand einbeziehen:
cqi/cqb(logische Inline-/Blockeinheiten),cqw/cqh(physische Einheiten),cqmin/cqmax. - Geben Sie dem Container immer eine feste
block-size, wenncontainer-type: sizeverwendet wird. Ohne diese werden untergeordnete Elemente minimiert, da die Größenbeschränkung den Container dazu zwingt, seinen Inhalt zu ignorieren.
Nicht empfohlen:
- Verwenden Sie
block-sizenicht alscontainer-type-Wert, da er ungültig ist. Verwenden Siesizefür beide Achsen. - Nachdem Sie
container-typedeklariert haben, sollten Sie nicht erwarten, dass die intrinsische Größe der untergeordneten Elemente den Container beeinflusst. Der Container wird so berechnet, als hätte er keine untergeordneten Elemente, sobald die Eingrenzung aktiv ist. - Verlassen Sie sich nicht auf Containerabfrageeinheiten in Nachfolgern eines nicht qualifizierten Vorfahren. Sie greifen auf den kleinen Darstellungsbereich (
svw/svh) zurück.
4.1 Codebeispiel: Flüssige Typografie mit Containerabfrageeinheiten
.card-wrapper {
container: card / inline-size; /* shorthand for container-name / container-type */
}
@container card (inline-size > 400px) {
.content {
display: flex;
gap: 2rem;
}
}
.title {
/* Fluid type bound to the container width, not the viewport. */
font-size: clamp(1rem, 4cqi, 2rem);
}
Informationen zu komponentenorientierten responsiven Styling-Mustern finden Sie unter Größenabhängiges Styling und Fluide Skalierung.
5 Native Overlays, Ankerpositionierung und Stapelkontexte
Wann sollte welches Overlay-Primitive verwendet werden?
- Verwenden Sie
popoverfür vorübergehende, nicht modale UI-Elemente (Flyouts, Toasts, Kurzinfos). Diese befinden sich in der obersten Ebene und erfordern keinez-index-Verwaltung. - Verwenden Sie
<dialog>mit.showModal()für modale Interaktionen, die ein Focus Trapping und einen inerten Hintergrund erfordern. - Kombinieren Sie
popoverund.showModal()nicht für dasselbe Element, da es sich um sich gegenseitig ausschließende Laufzeitstatus handelt.
Ankerpositionierung (räumliches Layout von Overlays):
- Verwenden Sie
position-area(oderanchor()bei Insets) undanchor-size(), um ein Overlay relativ zu seinem Trigger zu positionieren und seine Größe festzulegen. - Verwenden Sie
position-try-fallbacks: flip-block(oderflip-inline), damit der Browser das Overlay neu positioniert, wenn es über den Darstellungsbereich hinausgeht. - Mischen Sie keine physischen und logischen Keywords in einem einzelnen
position-area-Wert. Wählen Sie ein Koordinatensystem aus. - Führen Sie eine Feature-Erkennung mit
@supports (anchor-name: --x)durch und stellen Sie ein Fallback mit absoluter Position bereit.
Ausführliche Informationen zur Implementierung, zu Polyfill-Strategien und zur Referenz für den Wert
popoverfinden Sie unter Declarative Dialog and Popover Control und Position Aware Tooltips. Informationen zur Ankerpositionierung für Drop-down-Menüs, Flyouts und Tab-Indikatoren finden Sie unter Viewport-Aware Dropdowns und Anchor Positioning Tab Underline.
6 Überlauf-Tracking und Layoutstabilität
Layoutverschiebungen, Scrollleisten und Clipping vorhersehbar verwalten.
Das sollten Sie tun:
- Verwenden Sie
overflow: auto, damit Scrollleisten nur angezeigt werden, wenn der Inhalt tatsächlich überläuft. - Verwenden Sie
overflow: clip, um Inhalte ohne Scrollcontainer zu beschneiden. Mitoverflow-clip-marginkönnen Sie Überlauf zulassen. - Verwende
scrollbar-gutter: stable, um Platz für Scrollleisten zu reservieren und Layout Shifts zu verhindern, wenn Inhalte größer werden. - Verwenden Sie
overscroll-behavior: contain(odernone) für verschachtelte Scrollbereiche (z. B. Seitenleisten, Modale und Listen), um zu verhindern, dass Scrollketten auf die Seite übertragen werden, oderoverscroll-behavior: chainfür Zwischen-Scroll-Wrapper (z. B. Swipe-to-Reveal-Tracks), wenn übermäßiges Scrollen an einen übergeordneten Scroller weitergegeben werden soll, ohne dass ein lokaler Rubber-Band-Bounce ausgelöst wird. Verwenden Sie die Triade
-webkit-line-clamp+display: -webkit-box+-webkit-box-orient: verticalfür mehrzeilige Kürzungen. Trotz des Präfixes ist dieses Muster vollständig spezifiziert und nicht veraltet. Deklarieren Sie die Kurzschreibweiseline-clampohne Präfix daneben. Browser, die sie noch nicht unterstützen, ignorieren das Attribut einfach. Nicht empfohlen:Verwenden Sie nicht
overflow: scroll, wennautoausreicht.scrollerzwingt Scrollleisten, auch wenn es nichts zu scrollen gibt.Verwenden Sie
overflow: hiddennicht, wenn Sie nur Inhalte abschneiden möchten. Mithiddenwird ein Scrollcontainer erstellt, der programmatisch gescrollt werden kann.
.scrollable-list {
max-block-size: 400px;
overflow-y: auto;
scrollbar-gutter: stable; /* Reserve scrollbar space. */
overscroll-behavior: contain; /* No scroll chaining into the page. */
}
.snippet {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-clamp: 3; /* Ignored where unsupported. */
overflow: clip;
}
Ausführliche Informationen zu
overflow: clipundoverflow-clip-marginfinden Sie unter Overflow Clipping Control. Informationen zur Übergabe von verschachteltem Scrollen mitoverscroll-behavior: chainin einer Benutzeroberfläche, die durch Wischen eingeblendet wird, finden Sie unter Zum Einblenden wischen. Informationen zu Farbe, Größe und Design von Scrollleisten finden Sie unter Farbe oder Breite einer Scrollleiste anpassen, Dunkler Modus und Scrollleiste an Einstellungen für hohen Kontrast anpassen.
7 Viewport-Mechanismen und Track-Verteilung
- Verwenden Sie
dvh/dvwfür Container mit mobilem Layout, die Änderungen der Browser-UI berücksichtigen müssen (URL-Leiste wird minimiert/maximiert). - Verwenden Sie
100vwnicht für Layouts mit voller Breite, da die Breite der Scrollleiste ignoriert wird und es zu einem horizontalen Überlauf kommt. Verwenden Sie stattdessen100%,100dvwoder100svw.
Informationen zum Einstiegspunkt für responsives Design (dynamische Darstellungsbereichseinheiten, Platz für Medien reservieren, fließende Typografie) finden Sie unter Responsives Design.
8 Rasterspalten (auch Masonry genannt)
Die Spezifikation wird unter dem Namen „Grid Lanes“ (z.B. display: grid-lanes) entwickelt, während frühere experimentelle Prototypen grid-template-rows: masonry verwendeten.
Das sollten Sie tun:
- Verwenden Sie heute ein Raster mit
grid-auto-flow: densefür eine dichte Anordnung und akzeptieren Sie, dass die DOM-Reihenfolge möglicherweise nicht der visuellen Reihenfolge entspricht. - Verwenden Sie mehrspaltige Layouts (
columns: 3; column-gap: 1rem) für inhaltsreiche, kachelartige Darstellungen, wenn die Elemente Dokumentfragmente und keine gleichwertigen Karten sind. - Behandle
grid-template-rows: masonrynur als progressive Verbesserung – verwende@supportsfür die Feature-Erkennung.
Nicht empfohlen:
- Machen Sie
grid-template-rows: masonryerst dann zu einer harten Anforderung, wenn Ihr Baseline-Ziel erreicht ist.
.gallery { columns: 3 200px; column-gap: 1rem; }
.gallery > * { break-inside: avoid; margin-block-end: 1rem; }
@supports (grid-template-rows: masonry) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
columns: unset;
}
}