Zur Suche springen Zur Navigation springen Zum Hauptinhalt springen Zum Footer springen

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.

Schulungen von kulturbanause

Intensive Trainings mit hohem Praxisbezug.

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-width: 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.

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-width: 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-width: 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:

  • cqwwidth des Container Queries
  • cqhheight des Container Queries
  • cqiinline-size des Container Queries
  • cqbblock-size des Container Queries
  • cqmin = Der kleinere Wert von cqi und cqb
  • cqmax = Der größere Wert von cqi und cqb

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-width: 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% Höhe des Browserfensters eingenommen hat (50vh). Zusätzlich soll sich die Komponente verändern, wenn inner 80% der Breite von outer eingenommen hat (80cqw).

@container outer (min-height: 50vh) {
    .component {
        background: grey;
        color: white;
    }
}

@container inner (min-width: 80cqw) {
    .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 Webdesign Agentur kulturbanause® und des kulturbanause® Blogs. Er übernimmt Projektleitung, UX/UI und Frontend-Development und hat zahlreiche Fachbücher und Video-Trainings veröffentlicht. Als Dozent leitet er Schulungen und Workshops. Am liebsten beschäftigt er sich mit Projekten und Themen, die ihn gleichermaßen konzeptionell als auch gestalterisch und technisch fordern.

Jonas Hellwig bei Xing

Feedback & Ergänzungen – 3 Kommentare

  1. 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 (Autor)
      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
  2. 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 →