CSS Container Queries mit @container

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.

Wann Media Queries an ihre Grenzen stoßen

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.

Das Beispiel Layout mit vier Layoutvarianten

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.

Auf anderen Unterseiten soll die Card in der Desktop-Version blau sein und den Bildbereich über dem Text zeigen

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:

Fehldarstellung durch den Einsatz des Media Queries

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.

Beispiel für ein mit CSS Container Queries umgesetzte Komponente. Zu Sehen ist die Ansicht für wenig Platz sowie die Ansicht für viel Platz.
Die Card als Komponente mit eigenem 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 in neuem Tab öffnen

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%;
  }
}
Video-Screenshot des Beispiels

Beispiel in neuem Tab öffnen

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:

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.

Data on support for the css-container-queries feature across the major browsers from caniuse.com

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

Benutzerbild

Jonas ist Gründer der Agentur kulturbanause und des kulturbanause Blogs. 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.

Jonas Hellwig bei Xing

Feedback & Ergänzungen – 8 Kommentare

  1. Markus
    schrieb am 26.02.2024 um 21:39 Uhr:

    Wo genau liegt denn der Unterschied zwischen cqw und cqi. Beide Angaben beziehen sich doch auf die (gleiche?) länge?

    Antworten
    • Jonas Hellwig
      schrieb am 27.02.2024 um 06:38 Uhr:

      Das sind zwei verschiedene Schreibweisen, die in unserer Leserichtung (links oben nach rechts unten) identisch sind. cqi bezeichnet die Inline-Achse. Diese Schreibweise ist moderner und robuster und Teil der sog. Logical Properties von CSS.

      Antworten
  2. Isabell
    schrieb am 01.03.2023 um 15:09 Uhr:

    Bis vor den Container Queries war es so, dass man die Schriftgröße und auch die Breite von Containern und deren margin und padding in der Einheit rem angeben sollte, damit sich diese Elemente an die vom Nutzer im Browser eingestellte Schriftgröße anpassen, aber mit den Container Query Units funktioniert das nicht mehr so.
    Wenn die Standardschriftgröße im Browser von 16 auf 18 erhöht wird, dann ändert sich zwar die Breite eines Containers entsprechend, wenn die Breite in rem angegeben ist, aber die Schriftgröße erhöht sich nach dem, was ich bisher gesehen und ausprobiert habe, nicht in dem Maß, wie es eigentlich gewünscht ist.

    Antworten
  3. Kolja
    schrieb am 08.12.2022 um 03:47 Uhr:

    Sehr gut erklärt, jetzt nur noch daraf warten, das Firefox unter Android die CQ endlich auch unterstützt

    Wie findet man raus, wann das soweit ist?

    Gruß Kolja

    Antworten
    • Jonas Hellwig
      schrieb am 08.12.2022 um 06:39 Uhr:

      Soweit ich informiert bin, sind CQ sind Kürze im nächsten Firefox Nightly und dann ab Firefox 109 in der normalen Version mit dabei.

      Antworten
  4. Fragsch
    schrieb am 07.10.2022 um 06:00 Uhr:

    Vielen Dank für die tolle Einführung in die Container-Queries! Top – wie immer.

    Folgende Kleinigkeit ist mir noch aufgefallen:
    Unter „Benannte Container“ schreibst du im CSS Beispiel „@container mein-name“ – denke, hier sollte es „@container mein-container“ heißen. Oder?

    Antworten
    • Jonas Hellwig
      schrieb am 07.10.2022 um 07:19 Uhr:

      Vielen Dank für deinen Kommentar! In der tat war der Container-Name abweichend zwischen Kommentar und @rule. Ich habe es korrigiert.

      Antworten
  5. Isabell
    schrieb am 16.09.2022 um 14:14 Uhr:

    Wieder mal ein sehr toller Artikel von dir, Jonas!

    Antworten

Kommentar zu dieser Seite

Wir freuen uns über Anregungen, Ergänzungen oder Hinweise zu Fehlern. Wir lesen jeden Eintrag, veröffentlichen aber nur, was den Inhalt sinnvoll ergänzt.

Design-Projekte mit kulturbanause

Unsere Leinwand ist der Browser und wir beschäftigen uns seit 2010 intensiv mit dem Thema Responsive Design. Wir realisieren flexible Web-Layouts und modulare Design Systeme.

Responsive Webdesign-Leistungsangebot →

Schulungen von kulturbanause

Wir bieten Seminare und Workshops zu den Themen Konzept, Design und Development. Immer up-to-date, praxisnah, kurzweilig und mit dem notwendigen Blick über den Tellerrand.

Übersicht Schulungsthemen →