Flexbox/Mehrspaltenlayout
In diesem Abschlusskapitel zeigen wir, wie man mit Flexbox eine Webseite mit mehreren Elementen erstellt, die sich problemlos an alle Viewports anpasst.
Das erste Beispiel aus dem Jahr 2018 schaltet das Layout mit Hilfe von Media Queries um.[1] Mittlerweile gibt es mit modernen CSS-Funktionen einige Möglichkeiten auf Medienabfragen zu verzichten.
Studiere die beiden Ansätze und entscheide am Schluss, welche Methode du bevorzugst.
Inhaltsverzeichnis
Flexbox mit Media Queries
body {
display: flex;
flex-flow: row wrap;
}
nav ul {
display: flex;
flex-direction: column;
}
/* Smart Phones und Tablets mit mittlerer Auflösung */
@media all and (width > 30em) {
aside {
flex: 1 1 auto; /* durch auto werden die beiden asides in eine Zeile gesetzt */
order: 4;
}
}
@media all and (width > 35em) {
nav ul {
flex-direction: row;
}
nav li {
flex: 1 1 0%;
}
}
/* Large screens */
@media all and (width > 50em) {
article {
order: 3;
flex: 5 1 0%;
}
aside {
flex: 2 1 0%;
}
#news {
order: 2;
align-self: center;
height: min-content;
}
}
Der body dieser Webseite dient als Flex-Container. flex-flow: row wrap; lässt die Elemente nebeneinander platzieren; bricht aber um, wenn der Platz nicht mehr ausreicht.
Anders die Navigation: Hier sorgt flex-direction: column dafür, dass die Navigationslinks untereinander dargestellt werden.
Bei einer Mindestbreite von @media all and (width > 30em) {} greift die erste Medienabfrage:
- die Aside-Boxen dürfen mit
flex: 1 1 auto;- grow (1) - normal wachsen, falls viel Platz vorhanden ist
- shrink (1) - normal schrumpfen , fals wenig Platz vorhanden ist
- (auto) - ihre natürliche Größe als Ausgangspunkt nehmen
(Der Browser verteilt die Breite je nach Platz anders: Der Satz nimmt mehr Breite ein als die Linkliste.)
Bei @media all and (width > 35em) {} greift die zweite:
- die Links der Navigation werden mit
flex-direction: row;nebeneinander angeordnet.
Bei einer Mindestbreite von @media all and (width > 50em) {} werden die Größenverhältnisse erneut geändert.
- der Article erhält mit
flex: 5 1 0%;einen größen flex-grow-Faktor als die aside-Boxen. - Der verfügbare Platz wird ausgenutzt, indem verschiedene Elemente mit order nach vorne oder hinten sortiert werden. Das schien 2018 revolutionär – diese Flexibilität irritiert aber, wenn man in den Elemente plötzlich mit der Tab-Reihenfolge durcheinanderkommt.
Intrinsisches Responsive Design
Flexbox verzichtet auf die festen Breitenangaben früherer fixed width layouts. Stattdessen berechnet der Browser anhand des verfügbaren Platzes die Größe und Anordnung der Flex-Items.
Reicht der Platz für eine horizontale Anordnung nicht mehr aus, können Media Queries oder Container Queries andere CSS-Regeln aktivieren und das Layout anpassen. Allerdings werden die CSS-Regeln eines Elements – etwa einer Navigation – dadurch häufig auf mehrere Stellen im Stylesheet verteilt. Dadurch wird der Zusammenhang zwischen den Regeln weniger offensichtlich.
Eine Alternative besteht darin, den Browser selbst entscheiden zu lassen, wann ein Layout umgebrochen werden muss. Dieses Prinzip wird als intrinsisches Responsive Design bezeichnet.
Intrinsisches Responsive Design bedeutet, dass sich ein Layout an den Anforderungen des Inhalts orientiert und nicht an festgelegten Geräteklassen oder Breakpoints.
Statt bei „30em zwei Spalten anzuzeigen“, beschreibt man, dass „jede Spalte mindestens 12em Breite benötigt“. Der Browser entscheidet dann selbst, wann Elemente umgebrochen, vergrößert oder verkleinert werden müssen.
Der Body – ein flexibler Container
Als Grundstruktur verwenden wir sowohl das Grundgerüst, als auch die Seitenstrukturierung aus dem HTML-Tutorial.
body {
display: flex;
flex-direction: column;
min-height: 100dvh;
max-width: 80em;
margin: auto;
}
Zuerst wird der Body vertikal unterteilt:
display: flex; und flex-direction: column; ordnen Header, Navigation, Inhalt und Footer untereinander an.
-
min-height: 100dvh;gibt der Seite mindestens die Höhe des sichtbaren Browserfensters. Die Einheit dvh (dynamic viewport height) berücksichtigt auf mobilen Browsern die tatsächlich sichtbare Höhe, ohne Adressleiste und Browser-UI, auch beim Scrollen. -
max-width: 80em;gibt der Seite eine maximale Breite.
Textzeilen, die sich über die gesamte Breite eines großen 4k-Monitors erstrecken, sind nur schwer lesbar.
Bei kleineren Viewports verringert sich die Breite, sodass die Seite nie breiter als der Bildschirm wird. -
margin: autozentriert die Seite.
Verwende für dein Layout keine festen Breitenangaben in Pixel. Wenn ein Benutzer die Schriftgröße im Browser ändert, wird im schlimmsten Fall das Layout zerschossen.
Breitenangaben in relativen Relativen Längenmaßen passen deine Webseite flexibel an die Schriftgröße an!
Header – Logo vs Slogan
Der Header ist ebenfalls ein Flex-Container.
header {
/* Header: Logo bleibt fest, der Slogan darf umbrechen. */
display: flex;
flex-wrap: wrap;
}
.logo {
/* horizontal zentriert, wenn in eigener Zeile */
margin: auto;
height: 3rem;
}
.logo img {
width: 3rem;
aspect-ratio: 1;
}
.slogan {
/* Der Slogan bricht um. */
flex: 1 1 22em;
}
Der Slogan erhält mit flex: 1 1 22em; eine flexible Breite und darf bei wenig Platz umbrechen. In diesem Fall wird das Logo mit margin: auto; in seiner separaten Zeile eingemittet.
Im Einstiegs-Tutorial hatten wir bereits eine Navigation, die mit Hilfe einer Media query umgeschaltet wurde, sobald der Bildschirm zu schmal wurde.
Mit Media Queries setzt Du einen festen Umschaltpunkt:
@container (width < 30rem) {
ul {
flex-direction: column;
}
}
Die Frage lautet dann: Warum gerade 30rem? Auf vielen Webseiten werden solche Werte durch Ausprobieren ermittelt. Ändert sich später der Inhalt, müssen die Breakpoints oft nachträglich angepasst werden.
Flexbox kann diese Entscheidung dem Browser überlassen. Anstatt feste Viewportbreiten vorzugeben, beschreiben wir lediglich, wie groß die Elemente mindestens sein sollen.
Im Beispiel sollen die Navigationspunkte möglichst in vier Spalten angeordnet werden. Jedes Element benötigt dafür etwa 12em Breite. Aus dieser Vorgabe wird die erforderliche Gesamtbreite berechnet:
Die Navigation nutzt flex-wrap: wrap;, damit die Listenelemente umbrechen können.
Ein einfaches flex: 1 1 12em; würde zwar funktionieren, kann aber bei mittlerer Breite zu einer unschönen Aufteilung von 3 + 1 Elementen führen.
nav ul {
--nav-gap: .7rem;
/* Grenze für 4 Elemente in einer Zeile. */
--nav-four-cols: calc(12em * 4 + var(--nav-gap) * 3);
display: flex;
flex-wrap: wrap;
gap: var(--nav-gap);
}
nav li {
/* clamp(): 4 nebeneinander, dann 2 x 2, dann einspaltig. */
flex: 1 1 clamp(12em, calc((var(--nav-four-cols) - 100%) * 999), calc((100% - var(--nav-gap)) / 2));
min-inline-size: min(100%, 12em);
}
Die Flex-Basis wechselt ohne Media Query zwischen drei Zuständen:
- Solange genügend Platz vorhanden ist, werden vier Elemente nebeneinander dargestellt.
- Wird der Platz knapper, sorgt clamp() dafür, dass die Flex-Items automatisch auf eine zweispaltige Anordnung wechseln.
- Reicht auch dafür der Platz nicht mehr aus, werden die Elemente einspaltig dargestellt.
Dies wird durch die clamp()-Funktion erreicht.
clamp(min, preferred, max)
Sie enthält drei Parameter:
- ein Minimum,
- einen bevorzugten Wert,
- und den erlaubten Maximalwert.
clamp(
12em,
calc((var(--nav-four-cols) - 100%) * 999),
calc((100% - var(--nav-gap)) / 2)
)
- Ein Menüpunkt wird nie kleiner als 12em.
-
calc((var(--nav-four-cols) - 100%) * 999)ist der eigentliche „Schalter“-
var(--nav-four-cols)ist die Breite, die 4 Menüitems brauchen würden -
var(--nav-four-cols) - 100%ist ein Vergleich;
positiv → Container ist zu klein für 4 Spalten
negativ → Container ist groß genug -
* 999: Das Ergebnis wird entweder sehr groß oder sehr klein
-
-
calc((100% - var(--nav-gap)) / 2): Der Maximalwert ist die größte sinnvolle Breite:- zwei Spalten nebeneinander
- mit gap berücksichtigt
Innerhalb von clamp() wird kein „fließender Wert“ berechnet, sondern ein Bereich definiert, in dem sich der Flex-Basiswert bewegen darf. Durch die Kombination aus Mindest-, Maximal- und einem bewusst extrem skalierten Mittelwert entsteht ein Verhalten, das abhängig vom verfügbaren Platz zwischen verschiedenen Layoutstufen umschaltet – ohne Media Queries.
Der Browser entscheidet also anhand der tatsächlich verfügbaren Breite und der Mindestgröße der Inhalte, wann umgebrochen wird. Es gibt keinen festen Breakpoint mehr, der manuell gewählt werden muss.
Dieses Verfahren wird manchmal als intrinsisches Responsive Design bezeichnet:
Nicht die Größe des Geräts bestimmt das Layout, sondern der Platzbedarf des Inhalts.
main – Die Hauptsache
Der Inhaltsbereich <main> ist wieder ein Flex-Container.
Mit flex-wrap: wrap; können <article> und <aside> nebeneinander stehen oder untereinander rutschen.
<article> bekommt mit flex: 1 1 40em; mehr Platz.
<aside> bekommt mit flex: 1 1 14em; eine kleinere, aber ebenfalls flexible Breite.
Cards - responsiv und flexibel
Die Kartenliste <div class="cards"> verwendet eine einfache Flexbox mit Umbruch:
display: flex;, flex-wrap: wrap; und gap verteilen die Karten mit gleichmäßigen Abständen.
Auch die einzelnen Karten sind als <section> Flex-Container.
Mit clamp() wird die Karte je nach verfügbarem Platz ein- oder zweispaltig.
Die direkten Kinder einer Karte erhalten flex: 1 1 15em;.
Dadurch können Bildbereich und Textbereich nebeneinander stehen oder untereinander umbrechen.
Der Bildplatzhalter nutzt wieder Zentrierung mit Flexbox.
aspect-ratio: 16 / 9; sorgt für ein gleichbleibendes Seitenverhältnis.
aside – keine Nebensache!
Das Formular ist in zwei Ebenen aufgebaut.
Der Formularcontainer ordnet die Formulargruppen mit flex-direction: column; untereinander an.
Jede Formulargruppe ist selbst ein Flex-Container. Beschriftung und Eingabefeld stehen nebeneinander, solange genug Platz vorhanden ist. Bei schmaler Breite brechen sie untereinander um.
Der Absende-Button bekommt mit flex: 1 1 100%; eine ganze Zeile.
So bleibt er unabhängig von der Breite gut erreichbar.
Das fertige Beispiel
Der Footer verwendet Flexbox zur Zentrierung, die darin enthaltenen 3 div erwarten als flex-basis 12em, andernfalls brechen sie um.
Fazit
Das Beispiel zeigt insgesamt, dass Flexbox nicht nur für große Layouts, sondern auch für kleine Ausrichtungsaufgaben nützlich ist. Mit flex, flex-wrap, gap, clamp(), min() und sinnvollen Mindestbreiten lassen sich viele responsive Layouts ohne Media Queries bauen.
Allerdings spricht nichts dagegen, bei Bedarf einfachere Lösungen mit Media Queries einzusetzen ;-)
Wie geht's weiter?
Mit diesem flexiblen Aufbau bist du für die Zukunft gerüstet.
Weitere Beispiele, in denen Flexbox eingesetzt wird:
Fertige Layouts mit Flexbox:
- Ihr Anwalt

- Man with Hat

- CSS-Garten

Neben Flexbox gibt es das neue Grid Layout mit dem du Elemente nicht nur entlang einer Achse, sondern zweidimensional frei und flexibel gestalten kannst. Die Media queries wurden kürzlich durch Container Queries erweitert, die sich nach der Breite der umgebenden Elements richten.
- ↑ Dieser Artikel erklärte in seiner ersten Version, wie man Mehrspaltenlayouts mit floats und Media Queries baute.
CSS/Anwendung und Praxis/mehrspaltige Layouts(web.archive.org)
2018 „entdeckten“ wir ihn wieder und bauten ihn mit Flexbox um.
2026 ist es erneut Zeit, neue Entwicklungen wieclamp()aufzunehmen.