Von: Jonas
Mit CSS Container Queries kann ein eigener Breakpoint pro Komponente festgelegt werden. Die @container-Regel wird klassisches Responsive Design revolutionieren.
Aktualisiert von 2021 – 8 Kommentare
Das Abfragen der Viewport-Größe ist mit Media Queries seit langem möglich und zentraler Bestandteil des Responsive Web Design (RWD). Allerdings haben sich in der Weiterentwicklung von RWD und in der parallelen Entwicklung hin zu modularen Layouts neue Anforderungen ergeben. Der Platz, den eine einzelne Komponente zur Verfügung hat, ist heute meist relevanter als die Breite des gesamten Browserfensters. Die Web-Community wünschte sich eine entsprechende Technologie und hat jahrelang an Übergangslösungen gearbeitet. Mit der CSS-Rule @container (sog. Container Queries) steht eine native CSS-Technik zur Verfügung.
Schauen wir uns zunächst ein Beispiel an, um zu verstehen worin der Vorteil von Container Queries liegt. Unser Beispiel-Layout beinhaltet eine typische Website-Komponente – die sog. Card – die aus Bildbereich und Inhalt besteht. Wenn die Card wenig Platz zur Verfügung hat, ist sie blau und das Bild soll über dem Inhalt stehen. Wenn mehr Raum verfügbar ist, soll das Bild nach links rutschen und die Card grün umgefärbt werden. Die Card besitzt also zwei verschiedene Zustände.

Wenn wir das Projekt mobile First aufbauen, stellt die blaue Card das Standardverhalten dar. Um bei einer Viewportbreite von 500 Pixeln auf die grüne Card umzuschalten, schreiben wir einen Media Query. Leider müssen wir ab 800 Pixeln das Verhalten widerrufen oder den Code umständlich zusammenfassen. Dadurch, dass das Verhalten von Seiten-Layout und Komponente im Code nicht sauber getrennt werden kann, entstehen sehr viele Kombinationsmöglichkeiten.
Das Problem: Redundanter Code für simple Anforderungen
Spätestens wenn weitere Layouts hinzukommen, müssen wir Sonderregeln schreiben, obwohl die Card keinen zusätzlichen Zustand einnimmt. Wie man sieht, soll die Card auf weiteren Unterseiten in der Desktopversion blau sein, da sie in der Seitenleiste bzw. dreispaltig dargestellt wird. Die einzelne Card hat somit nur wenig Raum zur Verfügung – vergleichbar mit der Ansicht auf kleinen Displays.

Da wir das Styling der Card bisher mit einem Media Query anhand der Viewportbreite festlegen, werden die falschen Stile angewandt. Das Ergebnis sähe ohne eine weitere Sonderlösung im Code wie folgt aus:

Die Lösung: Eigene Breakpoints pro Komponente
Wünschenswert ist eine Komponente die eigene Breakpoints besitzt und auf den verfügbaren Raum im Elternelement (dem Container) reagiert. In unserem Beispiel hätte die Komponente »Card« dann zwei Zustände und einen Breakpoint.

Syntax und Funktionsweise von @container
Mit CSS Container Queries kann ein eigener Breakpoint pro Komponente festgelegt werden. Die Komponente reagiert, sobald der Container (das Elternelement) eine bestimme Breite über- oder unterschreitet. Somit ist eine Trennung des Seitenlayouts vom Layout der Komponente möglich, was den Code deutlich vereinfacht.
Das folgende Beispiel zeigt die grundlegende Syntax mit @container. Sobald die Card breiter als 500px wird, soll sie von Blau auf Grün umgefärbt werden. Detail zur Syntax findet ihr in der Spezifikation für CSS Container Queries.
.container {
container-type: inline-size;
}
.card {
background: lightblue;
}
@container (min-inline-size: 500px) {
.card {
background: lightgreen;
}
}Bitte beachtet, dass .container die Eigenschaft container-type: inline-size; erhalten hat. .container ist in diesem Beispiel das Elternelement, auf das reagiert werden soll.
Der Befehl container-type: inline-size; informiert den Browser, dass der Container sich auf der Inline-Achse in der Größe verändern kann – also in unserem Beispiel in der Breite. Es gibt u.a. auch den Wert size für die Kombination aus Block- und Inline-Size. Die Angaben basieren auf den Logical Properties von CSS und sind abhängig von der Leserichtung des Layouts. Auch der Media Query ist nicht mit min-width formuliert (was allerdings funktionieren würde), sondern mit min-inline-size.
Wenn kein Container Query aktiviert werden soll, bzw. wenn ihr den Container Query zurücksetzen möchtet, verwendet den Wert normal. In Zukunft können wir wahrscheinlich, neben den hier gezeigten Size Queries, auch Style-Queries oder State-Queries verwenden.
Beispiel: Mehrspaltiges Layout mit CSS Container Queries
Schauen wir uns das zuvor beschriebene Beispiel vor dem Hintergrund von Container Queries noch einmal an. Der Grundaufbau im HTML folgt einem simplen Schema.
<main>
<div class="container">
<div class="card"> … </div>
</div>
<div class="container">
<div class="card"> … </div>
</div>
<div class="container">
<div class="card"> … </div>
</div>
<div class="container">
<div class="card"> … </div>
</div>
</main>Das mehrspaltige Layout wird mit einem intrinsischen CSS Grid hergestellt, dass dem <main>-Element zugewiesen wurde. Auffällig ist, dass der .container im HTML-Code mehrmals vorkommt, obwohl wir mit CSS Grid ein Raster erstellen. Das hängt damit zusammen, dass die Rasterzellen nicht als Container dienen können.
main {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(500px, 100%), 1fr));
grid-template-rows: 1fr 1fr 1fr 1fr;
margin: 0;
}Es folgt das Basis-Styling der Cards. Dieser Teil wird hier nur der Vollständigkeit halber abgebildet und ist für die Funktionsweise des Container Query-Layouts unerheblich.
.card {
--color:#257989;
--strokewidth: 2px;
color: var(--color);
border: var(--strokewidth) solid;
margin: 1em;
}
.card-header {
aspect-ratio: 20/9;
background: var(--color);
}
.card-content {
padding: 1em;
}
.card-btn {
padding: .8em 1.2em;
color: var(--color);
border: var(--strokewidth) solid var(--color);
background: none;
font-size: 1em;
}Der spannende Teil folgt jetzt. Die Klasse .container erhält mittels container-type die Angabe, dass die inline-size (hier Breite) ausschlaggebend für die Anpassung der Card ist.
Mit @container (min-inline-size: 560px) { } definieren wir eine Regel, die immer dann gilt, wenn der Container (hier .container) größer als 560 Pixel auf der Inline-Achse ist. Sobald das der Fall ist, definieren wir die CSS-Variable für die Farbe neu und ändern das Layout mit Flexbox.
.container {
container-type: inline-size;
}
@container (min-inline-size: 560px) {
.card {
--color: #8cb11c;
display: flex;
}
.card-header {
flex: 1 0 40%;
}
}Einheiten für CSS Container Queries
Die Spezifikation rund um Container Queries führt neben @container auch zahlreiche neue Einheiten ein. Wer mit den Einheiten vw, vh etc. für Viewports bereits vertraut ist, wird hier wenig Startschwierigkeiten haben.
Die Container Query Units lauten:
cqw=widthdes Container Queriescqh=heightdes Container Queriescqi=inline-sizedes Container Queriescqb=block-sizedes Container Queriescqmin= Der kleinere Wert voncqiundcqbcqmax= Der größere Wert voncqiundcqb
Beispiel: Schriftgröße abhängig vom Container ändern
Schauen wir uns ein Beispiel an, um besser zu verstehen welche Möglichkeiten Container Query Units bieten. Mit der CSS Eigenschaft clamp() definieren wir eine variable Schriftgröße mit einer Mindest- und einer Maximalgröße. Die mittlere Angabe in clamp() legt den Orientierungspunkt fest. Mit 5cqi gestalten wir eine dynamische Schriftgröße auf Grundlage von 5% der Inline-Größe des Containers.
<div class="container">
<div class="card"> … </div>
</div>.container {
container-type: inline-size;
}
.card {
font-size: clamp(1em, 5cqi, 2em);
}Wir haben zu diesem Beispiel eine interaktive Demo erstellt. Beispiel in neuem Tab öffnen
Container Query Names – Benannte Container
Elemente reagieren normalerweise auf Container, die in der HTML-Struktur direkte Elternelemente sind. Allerdings ist es möglich, mit Hilfe benannter Container auf nicht-direkte Elternelemente Bezug zu nehmen. Somit ist es z.B. auch möglich, verschiedene Eigenschaften unterschiedlicher Elternelemente für die Anpassung der Komponente zu verwenden.
Um einen benannten Container zu erzeugen, wird die Eigenschaft container-name verwendet. Innerhalb des Container Query wird der Name dann vor der Abfrage der Query-Eigenschaft angegeben. Es sind auch mehrere Namen möglich.
.container {
container-type: inline-size;
container-name: mein-container; /* Der Name kann frei vergeben werden */
}
/* Der Container »mein-container« wird angesprochen */
@container mein-container (min-inline-size: 500px) {
…
}Beispiel: Eigenschaften von verschiedenen Containern abfragen
Schauen wir uns an, wie Container Names in der Praxis funktionieren können. Das folgende Beispiel zeigt eine Komponente die im HTML zwei Mal verschachtelt wurde.
<div class="outer">
<div class="inner">
<div class="component"> … </div>
</div>
</div>Beide Elternelemente werden zu Containern umfunktioniert – allerdings mit unterschiedlichen Namen und Typen. Der Container outer reagiert dank container-type: size; auf die Block-Size (= Höhe), der Container inner reagiert, wie die zuvor gezeigten Beispiele, auf die Breite.
.outer {
container-type: size;
container-name: outer;
}
.inner {
container-type: inline-size;
container-name: inner;
}Nun folgen die Container Queries. Die Komponente soll sich verändern, wenn outer mindestens 50% Block-Size (hier Höhe) des Browserfensters eingenommen hat (50vb). Zusätzlich soll sich die Komponente verändern, wenn inner 80% der Inline-Size (hier Breite) von outer eingenommen hat (80cqi).
@container outer (min-block-size: 50vb) {
.component {
background: grey;
color: white;
}
}
@container inner (min-inline-size: 80cqi) {
.component {
border: 10px solid black;
}
}Wir haben eine interaktive Demo erstellt, anhand der ihr das Verhalten ausprobieren könnt. Beispiel in neuem Tab öffnen
Die Kurzschreibweise für einen Container Query
Es existiert auch eine Kurzschreibweise für Container Queries, die die Eigenschaften container-name und container-type zusammenfasst. dabei werden die Werte mit Slash getrennt in eine Zeile geschrieben. Zuerst der Name, dann der Typ.
/* Lange Schreibweise */
.container {
container-type: inline-size;
container-name: mein-container;
}
/* Kurze Schreibweise */
.container {
container: mein-container / inline-size;
} Browser Support
Den detaillierten Browser-Support für dieses Feature könnt ihr auf caniuse.com einsehen.
Fazit
Container Queries werden, ähnlich wie seinerzeit Media Queries, die Art wie wir Weblayouts und Komponenten entwickeln grundlegend verändern. Das Bedürfnis nach Lösungen dieser Art ist sehr groß – was auch Entwicklungen wie Intrinsic Design gezeigt haben. In Kombination mit CSS :has() und @layers stehen uns Möglichkeiten zur Verfügung, die komplexe und robuste Layouts mit wenig Code ermöglichen.
Geschrieben von:
Jonas Hellwig
![]()
Jonas ist Gründer von kulturbanause. Er arbeitet an der Schnittstelle zwischen UX/UI Design, Frontend und Redaktion und hat zahlreiche Fachbücher und Video-Trainings veröffentlicht. Jonas Hellwig ist regelmäßig als Sprecher auf Fachveranstaltungen anzutreffen und unterstützt mit Seminaren und Workshops Agenturen und Unternehmen bei der Planung, der Gestaltung und der technischen Umsetzung von Web-Projekten.