PFAD: ./module/css/css5/

DATEI: string(25) "00Inhaltsverzeichnis5.php"
DATEI: string(27) "35Respönsives-Webdesign.php"
DATEI: string(21) "36Flexible Größen.php"
DATEI: string(19) "38Media Queries.php"
DATEI: string(18) "39Mobile-First.php"
DATEI: string(23) "41Responsive Bilder.php"
DATEI: string(27) "42Responsive Typografie.php"
DATEI: string(25) "43Responsive Tabellen.php"
DATEI: string(23) "44Container Queries.php"
DATEI: string(21) "46Feature-Queries.php"

css mit Adi Prinz

Container Queries und responsive Komponenten

Media Queries reagieren normalerweise auf die Größe des Viewports. Eine Komponente weiß dadurch jedoch nicht, wie viel Platz ihr innerhalb des tatsächlichen Layoutbereichs zur Verfügung steht.

Container Queries ermöglichen es, die Darstellung einer Komponente von der Größe ihres umgebenden Containers abhängig zu machen. Dieselbe Komponente kann dadurch beispielsweise in einer schmalen Seitenleiste einspaltig und im breiten Hauptbereich mehrspaltig erscheinen.

Media Query und Container Query im Vergleich

Technik Reagiert auf Typischer Einsatz
@media Viewport oder Ausgabegerät Gesamtes Seitenlayout und globale Navigation
@container Größe oder Eigenschaften eines Containers Wiederverwendbare Komponenten
@media (min-width: 60rem) {
  .page-layout {
    grid-template-columns: 18rem 1fr;
  }
}

@container (min-width: 35rem) {
  .card {
    grid-template-columns: 12rem 1fr;
  }
}
    

Die Media Query verändert das übergeordnete Seitenlayout. Die Container Query verändert die Karte entsprechend dem Platz, den ihr eigener Container bereitstellt.

Einen Größencontainer definieren

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

Mit container-type: inline-size wird das Element zu einem Abfragecontainer. Container Queries können anschließend auf seine Größe entlang der Inline-Achse reagieren.

Bei horizontal geschriebenem Text entspricht die Inline-Achse normalerweise der Breite.

Die Container Query prüft nicht die Größe der Komponente selbst, sondern die Größe eines geeigneten übergeordneten Abfragecontainers.

Die erste Container Query

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

.card {
  display: grid;
  gap: 1rem;
}

@container (min-width: 30rem) {
  .card {
    grid-template-columns: 10rem 1fr;
    align-items: start;
  }
}
    

Solange der Container schmaler als 30rem ist, bleiben Bild und Inhalt untereinander. Ab einer Containerbreite von 30rem werden sie nebeneinander angeordnet.

container-type

Wert Bedeutung
normal Das Element ist kein Größencontainer. Style Queries können abhängig von der Unterstützung trotzdem möglich sein.
inline-size Größenabfragen beziehen sich auf die Inline-Abmessung des Containers.
size Größenabfragen können sich auf die Inline- und Block-Abmessung beziehen.
Für die meisten responsiven Komponenten ist inline-size die geeignete Wahl. Eine Abhängigkeit von der Höhe ist wesentlich seltener erforderlich.

Einen Container benennen

.main-content {
  container-name: content;
  container-type: inline-size;
}
    

Mit container-name erhält ein Abfragecontainer einen eindeutigen Namen. Eine Container Query kann dadurch gezielt auf diesen Container verweisen.

@container content (min-width: 45rem) {
  .article-card {
    grid-template-columns: 14rem 1fr;
  }
}
    

Die Kurzschreibweise container

.main-content {
  container: content / inline-size;
}
    

Die Eigenschaft container kombiniert den Namen und den Typ eines Abfragecontainers.

container: container-name / container-type;
    
Der Schrägstrich trennt den Namen des Containers von seinem container-type.

Unbenannte und benannte Container Queries

@container (min-width: 30rem) {
  .card {
    grid-template-columns: 10rem 1fr;
  }
}
    

Ohne Namen sucht der Browser beim Element nach dem nächsten geeigneten übergeordneten Abfragecontainer.

@container sidebar (min-width: 20rem) {
  .card {
    padding: 1.5rem;
  }
}
    

Mit einem Namen wird gezielt der passende übergeordnete Container verwendet.

Small Device First bei Container Queries

.product-card {
  display: grid;
  gap: 1rem;
  padding: 1rem;
}

.product-card img {
  width: 100%;
  height: auto;
}

@container (min-width: 28rem) {
  .product-card {
    grid-template-columns: minmax(9rem, 35%) 1fr;
    align-items: start;
  }
}

@container (min-width: 50rem) {
  .product-card {
    grid-template-columns: minmax(14rem, 40%) 1fr;
    padding: 2rem;
  }
}
    

Die Grunddarstellung ist für schmale Container geeignet. Zusätzliche Layoutmöglichkeiten werden erst aktiviert, wenn der Container ausreichend Platz bietet.

Bereichsabfragen verwenden

@container (30rem <= width < 50rem) {
  .card {
    grid-template-columns: 12rem 1fr;
  }
}
    

Mit der Bereichssyntax kann eine Darstellung auf einen bestimmten Größenbereich begrenzt werden. In diesem Beispiel gilt die Regel ab 30rem, aber noch nicht ab 50rem.

@container (width >= 50rem) {
  .card {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
    

Mehrere Bedingungen verbinden

@container (min-width: 35rem) and (max-width: 55rem) {
  .card {
    grid-template-columns: 12rem 1fr;
  }
}
    

Bedingungen können wie bei Media Queries mit and miteinander verbunden werden.

@container (width < 25rem) or (width > 60rem) {
  .card-title {
    font-weight: 800;
  }
}
    

Mit or genügt eine der angegebenen Bedingungen. Durch Klammern lassen sich komplexere Abfragen eindeutig strukturieren.

Container-relative Längeneinheiten

Einheit Bezug
cqw 1 % der Breite des Abfragecontainers
cqh 1 % der Höhe des Abfragecontainers
cqi 1 % der Inline-Abmessung des Abfragecontainers
cqb 1 % der Block-Abmessung des Abfragecontainers
cqmin Der kleinere Wert von cqi und cqb
cqmax Der größere Wert von cqi und cqb

Fließende Größen innerhalb einer Komponente

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

.card {
  padding: clamp(1rem, 4cqi, 2rem);
}

.card-title {
  font-size: clamp(1.25rem, 5cqi, 2.25rem);
}
    

Die Abstände und die Überschrift reagieren auf die Inline-Größe des Containers. Mit clamp() werden gleichzeitig sinnvolle Mindest- und Höchstwerte festgelegt.

Container-relative Einheiten sollten für Textgrößen nicht ohne Begrenzung verwendet werden. Andernfalls kann der Text zu klein oder zu groß werden.

Eine Komponente in unterschiedlichen Bereichen

.page-layout {
  display: grid;
  gap: 2rem;
}

.card-area {
  container-type: inline-size;
}

@media (min-width: 64rem) {
  .page-layout {
    grid-template-columns: minmax(0, 2fr) minmax(16rem, 1fr);
  }
}

@container (min-width: 35rem) {
  .news-card {
    display: grid;
    grid-template-columns: 12rem 1fr;
    gap: 1.5rem;
  }
}
    

Im breiten Hauptbereich kann der Container die erforderlichen 35rem erreichen. In der schmaleren Seitenleiste bleibt dieselbe Karte dagegen einspaltig.

Die Komponente benötigt keine Kenntnis darüber, ob sie sich im Hauptbereich, in einer Seitenleiste oder in einem anderen Layout befindet.

Vollständige HTML-Struktur einer responsiven Karte

<div class="card-wrapper">
  <article class="course-card">
    <img
      class="course-card-image"
      src="images/css-grid.jpg"
      alt="CSS-Grid-Beispiel auf einem Bildschirm"
    >

    <div class="course-card-content">
      <p class="course-card-category">Webdesign</p>

      <h3 class="course-card-title">
        Responsive Layouts mit CSS Grid
      </h3>

      <p>
        Das Beispiel zeigt einen flexiblen Seitenaufbau für unterschiedliche
        Container- und Viewportgrößen.
      </p>

      <a href="css-grid.php">Beispiel ansehen</a>
    </div>
  </article>
</div>
    

Vollständiges CSS der responsiven Karte

.card-wrapper {
  container: course-card / inline-size;
}

.course-card {
  display: grid;
  gap: 1rem;
  height: 100%;
  padding: 1rem;
  background-color: #ffffff;
  border: 1px solid #ced4da;
  border-radius: 0.75rem;
  box-shadow: 0 0.25rem 1rem rgb(0 0 0 / 0.08);
}

.course-card-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 0.5rem;
}

.course-card-content {
  display: grid;
  align-content: start;
  gap: 0.75rem;
  min-width: 0;
}

.course-card-category,
.course-card-title,
.course-card-content p {
  margin: 0;
}

.course-card-category {
  color: #6f42c1;
  font-weight: 700;
}

.course-card-title {
  font-size: clamp(1.25rem, 5cqi, 2rem);
  line-height: 1.2;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.course-card-content a {
  justify-self: start;
  padding: 0.625rem 1rem;
  color: #ffffff;
  background-color: #6f42c1;
  border-radius: 0.375rem;
  text-decoration: none;
}

.course-card-content a:hover {
  background-color: #59359a;
}

.course-card-content a:focus-visible {
  outline: 3px solid #fd7e14;
  outline-offset: 3px;
}

@container course-card (min-width: 32rem) {
  .course-card {
    grid-template-columns: minmax(10rem, 40%) 1fr;
    align-items: start;
    padding: clamp(1rem, 4cqi, 2rem);
  }

  .course-card-image {
    height: 100%;
    min-height: 12rem;
    aspect-ratio: auto;
  }
}

@container course-card (min-width: 52rem) {
  .course-card {
    grid-template-columns: minmax(16rem, 35%) 1fr;
  }

  .course-card-content {
    align-self: center;
  }
}
    

Verschachtelte Container

.dashboard {
  container: dashboard / inline-size;
}

.widget-area {
  container: widget / inline-size;
}

@container dashboard (min-width: 60rem) {
  .dashboard-layout {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@container widget (min-width: 25rem) {
  .statistic-card {
    grid-template-columns: auto 1fr;
  }
}
    

Container können verschachtelt werden. Das Dashboard reagiert auf seinen verfügbaren Platz, während die Statistik-Karte unabhängig davon auf die Breite ihres eigenen Widget-Bereichs reagiert.

Aussagekräftige Containernamen helfen dabei, bei verschachtelten Komponenten den richtigen Bezug eindeutig festzulegen.

Warum ein Element nicht sich selbst abfragen kann

/* Nicht wie erwartet */
.card {
  container-type: inline-size;
}

@container (min-width: 30rem) {
  .card {
    grid-template-columns: 10rem 1fr;
  }
}
    

Die Regel innerhalb einer Container Query bezieht sich auf einen übergeordneten Container. Die Karte kann nicht gleichzeitig der abgefragte Container und das Element sein, dessen eigene Gestaltung von dieser Abfrage abhängt.

/* Geeignete Struktur */
.card-wrapper {
  container-type: inline-size;
}

@container (min-width: 30rem) {
  .card {
    grid-template-columns: 10rem 1fr;
  }
}
    

Container benötigen eine verfügbare Breite

.cards-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: 1.5rem;
}

.card-wrapper {
  min-width: 0;
  container-type: inline-size;
}
    

Das äußere Grid bestimmt, wie viel Platz jeder Karte zur Verfügung steht. Der Wrapper misst diesen Platz und stellt ihn für die Container Query bereit.

min-width: 0 verhindert, dass lange Inhalte ein Grid-Element über seine vorgesehene Spaltenbreite hinaus vergrößern.

Media Queries und Container Queries kombinieren

.page-layout {
  display: grid;
  gap: 1.5rem;
}

.component-area {
  container-type: inline-size;
}

@media (min-width: 60rem) {
  .page-layout {
    grid-template-columns: 16rem minmax(0, 1fr);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .card {
    transition:
      transform 200ms ease,
      box-shadow 200ms ease;
  }

  .card:hover {
    transform: translateY(-0.25rem);
  }
}

@container (min-width: 35rem) {
  .card {
    grid-template-columns: 12rem 1fr;
  }
}
    

Media Queries bleiben für globale Layoutänderungen und Benutzereinstellungen wichtig. Container Queries ergänzen sie bei komponentenbezogenen Layoutänderungen.

Progressive Verbesserung mit @supports

.card {
  display: grid;
  gap: 1rem;
}

@supports (container-type: inline-size) {
  .card-wrapper {
    container-type: inline-size;
  }

  @container (min-width: 32rem) {
    .card {
      grid-template-columns: 12rem 1fr;
    }
  }
}
    

Die Grunddarstellung funktioniert auch ohne Container Query. Unterstützt der Browser die Technik, wird die erweiterte Darstellung aktiviert.

Die Basisversion einer Komponente sollte auch dann verständlich und benutzbar bleiben, wenn eine neuere CSS-Funktion nicht verfügbar ist.

Style Queries mit Custom Properties

.card-area {
  --card-theme: dark;
  container-name: card-theme;
}

@container card-theme style(--card-theme: dark) {
  .card {
    color: #ffffff;
    background-color: #212529;
  }
}
    

Style Queries können die Darstellung von Eigenschaften eines übergeordneten Containers abhängig machen. Besonders nützlich ist die Abfrage von Custom Properties, über die eine Komponente beispielsweise ein Darstellungsdesign erhalten kann.

Style Queries sind neuer als Größenabfragen. Vor dem produktiven Einsatz sollte die benötigte Browserunterstützung geprüft und eine funktionierende Grunddarstellung vorgesehen werden.

Container Queries mit JavaScript prüfen

if (CSS.supports("container-type: inline-size")) {
  document.documentElement.classList.add("supports-container-queries");
}
    

In den meisten Fällen genügt eine CSS-Abfrage mit @supports. JavaScript ist nur erforderlich, wenn die Unterstützung auch die Programmlogik beeinflusst.

Für reine Darstellungsänderungen sollte CSS verwendet werden. Eine Größenüberwachung mit JavaScript ist für normale Container-Query-Layouts nicht notwendig.

Häufige Fehler

  • Für das übergeordnete Element wurde kein container-type festgelegt.
  • Die Komponente versucht, ihre eigene Größe statt die Größe eines übergeordneten Containers abzufragen.
  • Eine unbenannte Container Query verwendet unbeabsichtigt den falschen übergeordneten Container.
  • Container Queries werden für globale Seitenänderungen verwendet, obwohl eine Media Query verständlicher wäre.
  • Breakpoints werden von bekannten Gerätebreiten übernommen, ohne den tatsächlichen Platzbedarf der Komponente zu berücksichtigen.
  • Es wird ausschließlich eine breite Darstellung definiert und keine robuste Grunddarstellung für schmale Container vorgesehen.
  • Container-relative Schriftgrößen werden ohne Mindest- und Höchstwerte verwendet.
  • Lange Inhalte verhindern, dass ein Grid- oder Flex-Element ausreichend schrumpfen kann.
  • Bei verschachtelten Containern fehlen eindeutige Namen.
  • Die Komponente wird nur im Hauptbereich, aber nicht in einer schmalen Seitenleiste oder einem kleinen Grid-Element geprüft.
  • Neue Techniken werden ohne funktionierende Grunddarstellung eingesetzt.

Zusammenfassung

  • Media Queries reagieren normalerweise auf den Viewport.
  • Container Queries reagieren auf den verfügbaren Platz eines übergeordneten Containers.
  • Mit container-type: inline-size wird ein Element zum Größencontainer für die Inline-Achse.
  • container-name weist einem Container einen eindeutigen Namen zu.
  • Die Kurzschreibweise container kombiniert Namen und Typ.
  • Eine benannte Abfrage beginnt beispielsweise mit @container content (...).
  • Container-Breakpoints sollten sich am tatsächlichen Platzbedarf der Komponente und nicht an bestimmten Geräten orientieren.
  • cqw, cqh, cqi und cqb beziehen sich auf Abmessungen eines Abfragecontainers.
  • clamp() kann container-relative Größen sinnvoll begrenzen.
  • Verschachtelte und benannte Container ermöglichen unabhängig reagierende Komponenten.
  • Media Queries und Container Queries ergänzen einander.
  • Eine robuste Grunddarstellung bleibt auch ohne Unterstützung neuerer CSS-Techniken nutzbar.
Container Queries ermöglichen wirklich wiederverwendbare Komponenten. Eine Karte, ein Formular oder ein Teaser passt sich nicht nur an den Viewport, sondern an den Platz an, der am jeweiligen Einsatzort tatsächlich verfügbar ist.