Links die klassische Anordnung von Mobile und Desktop Layout. Rechts das Karten-Modul mit Container Queries.

Hilfe, die CSS Container Queries kommen: Alles was du jetzt wissen musst

CSS Container Queries sind ein neuer Standard für Weblayouts, welcher im September 2022 im Chrome-Browser (in Version 105 und 106) gelandet ist. Safari ist mit Version 16 [1] ebenfalls schon nachgezogen.

Diagramm der Seite canisuse.com ab wann CSS Container Queries in Chrome unterstützt werden. Diese werden ab Chrome 106 voll unterstützt.
Container Queries werden ab Chrome 106 unterstützt. Safari ist mit Version 16 ebenfalls schon nachgezogen. Quelle: caniuse.com

In diesem Artikel werde ich ausführen, wofür Container-Queries besonders gut geeignet sind, wie sie die Web-Entwicklung vereinfachen werden und wie du damit moderne, responsive Weblayouts erstellen kannst.

Was genau sind Container Queries?

Mit Container-Queries kannst du Komponenten einer Website so gestalten, dass sie sich je nach Größe des übergeordneten Elements (des Containers) anpassen. Dadurch kannst du vermeiden, dass sie je nach Breite des Bildschirms zu gedrängt oder zu breit aussehen.

Links die klassische Anordnung von Mobile und Desktop Layout. Rechts das Karten-Modul mit Container Queries.
Bei Media Queries wird die Komponente anhand der Breite (oder Höhe) des Viewports definiert. Bei Container-Queries ist der Bezug jedoch die (Breite der) übergeordnete Komponente.

Wozu sind CSS Container Queries gut?

Von Tabellen bis hin zu den Karten-Modulen kannst du CSS Container Queries so einsetzen, dass sie verschiedene Probleme lösen, ohne dass du dafür JavaScript benötigst.

Beispiele für Container Queries:
11 Beispiele, von dir Container Queries die Arbeit erleichtern werden: Zeitleisten, Karten, Tabellen, Paginierung, Zitate und vieles andere mehr.

Was ist das Problem bei CSS Media Queries?

Eine Webseite besteht üblicherweise aus verschiedenen Abschnitten und Komponenten, die wir mithilfe von CSS Media-Queries responsiv machen. Das Problem hierbei? Oft geht es beim responsiven Webdesign eigentlich nicht um den Viewport oder die Bildschirmgröße, sondern um die Breite des übergeordneten Containers.

Zwei typische Layouts. Links die Anordnung für Mobile View untereinander. Rechts die Anordnung in zwei Spalten.
Ein typisches Layout, das mit Karten arbeitet. Links die Anordnung untereinander, rechts die Anordnung in mehreren Spalten. Auch das innere Layout der Karten ändert sich hierbei.

Im Beispiel oben haben wir ein typisches, Karten-basiertes Layout, das es in zwei Varianten gibt:

  • a) Die Karten werden übereinander angeordnet (linke Spalte)
  • b) Die Karten werden nebeneinander angeordnet (rechte Spalte)

Schauen wir uns folgendes Beispiel an: Wir haben eine Kartenkomponente, die zu einer inneren horizontalen Anordnung hin wechseln soll, wenn genug Platz vorhanden ist.

Vergleich einer Karten-Komponente in vertikaler und horizontaler Anordnung.
Vergleich einer Karten-Komponente in vertikaler und horizontaler Anordnung.

Es gibt mehrere Möglichkeiten, dieses Layout ins CSS umzusetzen. Die häufigste ist die folgende: Wir erstellen eine Basiskomponente, und variieren diese je nach Breite des Bildschirms.

.c-article {
  /* Basisversion, Karten sind übereinander angeordnet */
}
.c-article > * + * {
  margin-top: 1rem;
}

/* Ab 46rem werden die Karten nebeneinander angeordnet */
@media (min-width: 46rem) {
  .c-article--horizontal {
    display: flex;
    flex-wrap: wrap;
  }

  .c-article > * + * {
    margin-top: 0;
  }

  .c-article__thumb {
    margin-right: 1rem;
  }
}

Beachte, dass wir die Klasse .c-article--horizontal erstellt haben, um die horizontale Version der Komponente zu definieren. Diese kommt ins Spiel, sobald die Breite des Viewports größer als 46 rem ist. Besser wäre es aber, wenn die Komponente direkt auf die Breite ihres übergeordneten divs reagiert, nicht nur auf die Bildschirmgröße.

Nehmen wir an, wir wollen die (mobile) Standard-.c-card auch auf Desktop (bzw. ab 46rem Bildschirmbreite) verwenden. Was passiert? Die Karten werden zu klobig, wie in der folgenden Abbildung zu sehen ist:

Linke Spalte das vertikale Mobile Layout. Rechts auf Desktop sehen die Karten auch so aus wie auf Mobile, nur viel zu klobig und groß.
Dank Media Queries werden die Karten-Komponenten auf Desktop zwar nebeneinander dargestellt, aber auch viel zu groß skaliert. Die Komponente an sich wird zwar größer, ändert aber nicht ihr Layout.

Dieses Problem bekommen wir Dank CSS Container Queries jetzt gelöst. Im Beispiel oben ist unser Wunschszenario, dass wenn der übergeordnete Container größer als 400 Pixel ist, sich das Layout der Karte zum horizontalen Stil hin ändern soll. Zunächst das Markup (HTML):

<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
</div>

Das CSS mit der @container Query wird so aussehen:

.o-grid__item {
  container-type: inline-size;
}
.c-article {
  /* The default style */
}
@container (min-width: 400px) {
  .c-article {
    /* The styles that will make the article horizontal**
        ** instead of a card style.. */
  }
}

Wie genau kommen jetzt CSS Container Queries ins Spiel?

Mit CSS-Container-Abfragen können wir eine Komponente erstellen, die ihr inneres Layout je nach vorhandenem Platz automatisch anpasst. Im folgenden siehst du, wie ich mir das vorstelle.

Links die klassische Anordnung von Mobile und Desktop Layout. Rechts das Karten-Modul mit Container Queries.
Bei Media Queries wird die Komponente anhand der Breite (oder Höhe) des Viewports definiert. Bei Container-Queries ist der Bezug jedoch die (Breite der) übergeordnete Komponente.

Die violette Klammer stellt die übergeordnete Breite dar. Die Komponente passt sich automatisch an ihre Umgebung (an den übergeordneten Container) an, wenn diese größer wird.

Wie funktionieren CSS Container-Queries?

Der erste Schritt besteht darin, die Eigenschaft container-type hinzuzufügen. Da sich eine Komponente auf der Grundlage ihrer übergeordneten Breite anpasst, müssen wir dem Browser mitteilen, dass nur der betroffene Bereich neu gezeichnet werden soll, nicht die gesamte Seite. Mit der Eigenschaft container-type können wir dem Browser dies im Voraus mitteilen.

Der Wert inline-size bedeutet, dass nur auf Änderungen der Breite des Elternteils reagiert werden soll.

<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <!-- other articles.. -->
</div>
.o-grid__item {
  container-type: inline-size;
}

Dies ist der erste Schritt. Wir haben das Element .o-grid__item als Containment Parent für das Element .c-article definiert.

Im nächsten Schritt fügen wir die Stile hinzu, die wir für die Containerabfragen benötigen.

.o-grid__item {
  container-type: inline-size;
}
@container (min-width: 400px) {
  .c-article {
    display: flex;
    flex-wrap: wrap;
  }

  /* other CSS.. */
}

Der @container ist das .o-grid__item Element und min-width: 400px ist die erforderliche Mindestbreite. Wir können sogar noch weiter gehen und weitere Stile hinzufügen. Hier ist ein Video, das zeigt, was man mit der Kartenkomponente erreichen kann:

Die Stile, die wir dort haben, sind:

  1. Der Standard, ein kartenähnliches Aussehen.
  2. Eine horizontale Karte mit einem kleinen Vorschaubild.
  3. Eine horizontale Karte mit einem großen Vorschaubild.
  4. Wenn das übergeordnete Element zu groß ist, wird der Stil hero-like, um anzuzeigen, dass es sich um einen vorgestellten Artikel handelt.

Sehen wir uns nun die Anwendungsfälle für CSS-Container-Abfragen an.

Wie sieht die Syntax bei Container Queries aus?

Um eine Komponente basierend auf ihrer übergeordneten Breite abzufragen, brauchen wir die Eigenschaft container-type . Hier ein einfaches Beispiel:

.wrapper {
  container-type: inline-size;
}

Damit können wir beginnen, eine Komponente abzufragen. Im folgenden Beispiel, wenn der Container der .card Element hat eine Breite gleich 400px oder größer ist, müssen wir einen bestimmten Stil hinzufügen.

@container (min-width: 400px) {
  .card {
    display: flex;
    align-items: center;
  }
}

Das funktioniert zwar, kann aber etwas unübersichtlich werden, wenn du mehrere Container hast. Um das zu vermeiden, ist es besser, einen Container zu benennen.

.wrapper {
  container-type: inline-size;
  container-name: card;
}

Jetzt können wir den Containernamen wie folgt an @container anhängen:

@container card (min-width: 400px) {
  .card {
    display: flex;
    align-items: center;
  }
}

Gehen wir noch einmal auf das ursprüngliche Beispiel ein und sehen wir uns an, wie wir von Container-Abfragen profitieren können, um mehrere CSS-Klassen zu vermeiden.

.wrapper {
  container-type: inline-size;
  container-name: card;
}
.c-article {
  /* Default stacked style */
}
@container card (min-width: 400px) {
  /* Horizontal style. */
  .c-article {
    display: flex;
    align-items: center;
  }
}

Anwendungsfälle für CSS Container Queries

Container-Abfragen und CSS-Grid mit auto-fit

In einigen Fällen kann die Verwendung von auto-fit im CSS-Grid zu unerwarteten Ergebnissen führen. Zum Beispiel wird eine Komponente zu breit und ihr Inhalt ist schwer zu lesen.

Um dir den Zusammenhang besser zu verdeutlichen, findest du hier eine Grafik, die den Unterschied zwischen auto-fill und auto-fit in CSS Grid zeigt.

Unterschiede zwischen CSS Grid auto-fit und auto-fill.

Beachte, dass sich die Elemente bei der automatischen Anpassung mit auto-fit so erweitert, dass sie den verfügbaren Platz ausfüllen. Im Falle von auto-fill wachsen die Elemente des Grids jedoch nicht und es bleibt stattdessen ein freier Platz (das gepunktete Element ganz rechts oben).

Du fragst dich jetzt vielleicht, was das mit CSS-Container-Abfragen zu tun hat? Jedes Grid-Element ist ein Container. Wenn dieser Container mit auto-fit erweitert wird, müssen wir die Komponente anpassen:

<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
</div>
.o-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 1rem;
}

Wenn wir vier Elemente haben, sollte das Ergebnis in etwa so aussehen.

Klassische, horizontale Anordnung von 4 Karten-Elementen.
Eine typische Anordnung von 4 Karten-Elementen.

Das wird sich ändern, wenn die Anzahl der Artikel geringer ist. Je weniger Artikel wir haben, desto breiter werden sie. Der Grund dafür ist, dass auto-fit verwendet wird. Mit vier oder drei Elementen nebeneinander sieht das noch gut aus, aber die letzten beiden Beispiele werden zu breit.

Vergleich verschiedener Anzahl von Karten nebeneinander.
Sobald nur noch zwei oder 1 Karte auf einer Zeile erscheint, werden die Karten zu breit.

Wie wäre es, wenn sich jede Artikelkomponente basierend auf der Breite der übergeordneten Komponente ändert? Auf diese Weise können wir die Vorteile von auto-fit nutzen. Dazu müssen wir folgendes tun:

Wenn die Breite des Grid-Elements größer als 400px ist, sollte der Artikel zum horizontalen Stil wechseln.

Und so setzen wir dies um:

.o-grid__item {
  container-type: inline-size;
}
@container (min-width: 400px) {
  .c-article {
    display: flex;
    flex-wrap: wrap;
  }
}

Außerdem wollen wir den Artikel mit einem Hero-Abschnitt anzeigen, wenn er der einzige Artikel im Raster ist.

.o-grid__item {
  container-type: inline-size;
}
@container (min-width: 700px) {
  .c-article {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 350px;
  }

  .card__thumb {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}
Mehrere Karten pro Zeile im Vergleich. Sind die Karten jeweils breiter als 400px, ändert sich ihr inneres Layout auf horizontal.
Sind die Karten jeweils breiter als 400px, ändert sich ihr inneres Layout.

Das war’s. Wir haben eine Komponente, die auf die Breite ihres übergeordneten Containers reagiert und zu jedem Kontext passt.

Desöfteren müssen wir eine Komponente so anpassen, dass sie auch in einem schmalen Container passt, wie z. B. in einer <aside>.

Ein perfektes Beispiel dafür ist eine Newsletter-Box. Wenn die Breite gering ist, müssen die einzelnen Elemente vertikal angeordnet werden. Wenn hingegen genug Platz vorhanden ist, sollen sie horizontal mitwachsen.

Darstellung einer Newsletter Box in einer schmalen Sidebar und in einer breiten Spalte.
Darstellung einer Newsletter Box in einer (schmalen) Sidebar und in einer breiten Hauptspalte.

Wie du in der Abbildung siehst, haben wir eine Newsletter-Box, die in zwei verschiedenen Kontexten angezeigt werden soll:

  • Links in einer Sidebar
  • Rechts in der Content-Spalte

Das CSS dafür sieht so aus:

.newsletter-wrapper {
  container-type: inline-size;
}
/* The default, stacked version */
.newsletter {
  /* CSS styles */
}
.newsletter__title {
  font-size: 1rem;
}
.newsletter__desc {
  display: none;
}
/* The horizontal version */
@container (min-width: 600px) {
  .newsletter {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .newsletter__title {
    font-size: 1.5rem;
  }

  .newsletter__desc {
    display: block;
  }
}

Hier das Video mit dem Ergebnis.

Link zur Demo auf CodePen.

Paginierung

Paginierungen eignen sich ebenfalls sehr gut für die Verwendung von Container-Queries. Am Anfang haben wir die Schaltflächen „Zurück“ und „Weiter“. Je nach vorhandenem Platz können wir dann noch die einzelnen Unterseiten anzeigen, wie in folgender Abbildung zu sehen ist.

Die Paginierung in verschiedenen Bildschirmgrößen im Vergleich.

Um das Layout oben zu erhalten, verwenden wir folgendes CSS:

.wrapper {
  container-type: inline-size;
}
@container (min-width: 250px) {
  .pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .pagination li:not(:last-child) {
    margin-bottom: 0;
  }
}
@container (min-width: 500px) {
  .pagination {
    justify-content: center;
  }

  .pagination__item:not(.btn) {
    display: block;
  }

  .pagination__item.btn {
    display: none;
  }
}

Link zur Demo auf CodePen.

Nutzerprofile

Ein Nutzerprofil in der Mobilen und in der Desktop-Ansicht.
Ein Nutzerprofil in der Mobilen und in der Desktop-Ansicht.

Hier ein weiterer Fall, der sich sehr gut eignet, um in verschiedenen Kontexten eingesetzt zu werden. Das kleine Nutzerprofil links eignet sich für mobile Ansichtsgrößen oder Umgebungen wie in einer Sidebar. Die größere Ansicht kannst du hingegen zum Beispiel in mehrspaltigen Layouts einsetzen.

.p-card-wrapper {
  container-type: inline-size;
}
.p-card {
  /* Default styles */
}
@container (min-width: 450px) {
  .meta {
    display: flex;
    justify-content: center;
    gap: 2rem;
    border-top: 1px solid #e8e8e8;
    background-color: #f9f9f9;
    padding: 1.5rem 1rem;
    margin: 1rem -1rem -1rem;
  }

  /* and other styles */
}

So können wir ein und dieselbe Komponente in verschiedenen Kontexten einsetzen, ohne eine einzige Media-Query verwenden zu müssen.

Nutzerprofile in einer Sidebar und in der Haupt-Spalte.

Link zur Demo auf CodePen.

Kontaktformulare

Hier ein möglicher Anwendungsfallen für Kontaktformulare, in welchem sich das Layout dem übergeordneten Container anpasst.

Kontaktformular in der mobilen und desktop-Ansicht.

.form-item {
  container-type: inline-size;
}
.input-group {
  @container (min-width: 350px) {
    display: flex;
    align-items: center;
    gap: 1.5rem;

    input {
      flex: 1;
    }
  }
}

Link zur Demo auf CodePen.

Ist es möglich, Fallbacks für Container Queries einzubauen?

Ja, es ist möglich, Containter Query-Fallbacks einzurichten. Hier sind zwei tolle Artikel, die erklären, wie man das macht:

1. Caniuse Container Queries

2. Webkit Safari 16

3. Versuchslabor von Ahmad Shadeed

4. Jen Simmons CSS Grid Experiments

Wie hilfreich fanden Sie diese Seite?

Durchschnittliche Bewertung 5 / 5. Anzahl Bewertungen: 2

Ähnliche Beiträge

2 Kommentare

  1. Danke für diesen tollen Artikel.
    Hat mir sehr geholfen, diese Thematik zu verstehen.
    Wäre schön, wenn es noch Infos und Erklärungen zu CSS Container Query Units (cqw, usw.) geben würde.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert