Modernes CSS-Layout: Container Queries und Subgrid
Praxisnahe Anleitung für responsive Layouts mit CSS Container Queries und Subgrid: Komponenten-Responsiveness, Ausrichtung, Karten-Raster, Dashboards.

Jenseits von Media Queries: Reaktionsfähigkeit auf Komponentenebene
Media Queries reagieren auf den Viewport. Container Queries reagieren auf den übergeordneten Container. Dieser Unterschied verändert grundlegend, wie wir wiederverwendbare Komponenten bauen. Eine Card-Komponente, die sich an ihren Container anpasst, funktioniert korrekt – egal ob sie in einer schmalen Sidebar, einem zweispaltigen Layout oder einer Hero-Sektion in voller Breite platziert wird –, ohne dass ihr CSS für jeden Kontext angepasst werden muss.
Container Queries und Subgrid sind die beiden einflussreichsten CSS-Layout-Features seit Grid selbst. Zusammen lösen sie Probleme, die das responsive Design seit über einem Jahrzehnt plagen.
Grundlagen von Container Queries
Container Queries erfordern, dass zunächst auf einem übergeordneten Element ein Containment-Kontext deklariert wird, bevor Abfragen gegen die Abmessungen dieses Containers geschrieben werden.
/* ❌ Media queries — component responds to viewport, not context */
.card {
display: flex;
flex-direction: column;
}
@media (min-width: 768px) {
.card {
flex-direction: row;
}
}
/* Problem: this card in a 300px sidebar still goes horizontal
on a 768px viewport — wrong layout for its context */
/* ✅ Container queries — component responds to its container */
.card-container {
container-type: inline-size;
container-name: card-wrapper;
}
.card {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
@container card-wrapper (min-width: 400px) {
.card {
flex-direction: row;
align-items: center;
}
.card__image {
flex: 0 0 40%;
max-width: 200px;
}
.card__content {
flex: 1;
}
}
@container card-wrapper (min-width: 600px) {
.card {
padding: 1.5rem;
gap: 1.5rem;
}
.card__title {
font-size: 1.5rem;
}
}Die Card passt sich jetzt an jeden Container an, in dem sie platziert wird, unabhängig von der Viewport-Größe. Platziere sie in einer schmalen Sidebar, und sie stapelt sich vertikal. Platziere sie in einem breiten Inhaltsbereich, und sie richtet sich horizontal aus. Media Queries sind dafür nicht nötig.
Container-Query-Einheiten
Mit Container-Query-Einheiten (cqi, cqb, cqw, cqh) lassen sich Elemente relativ zu den Abmessungen des Containers dimensionieren – nicht zum Viewport.
.card-container {
container-type: inline-size;
}
.card__title {
/* Font size scales with container width */
font-size: clamp(1rem, 3cqi, 1.5rem);
}
.card__description {
font-size: clamp(0.875rem, 2cqi, 1.125rem);
line-height: 1.6;
}
.card__image {
/* Image height proportional to container */
height: clamp(120px, 30cqi, 250px);
object-fit: cover;
border-radius: 0.5rem;
}<!-- The same component works in any layout context -->
<div class="grid" style="grid-template-columns: 1fr 2fr 1fr;">
<div class="card-container">
<!-- Narrow: stacked, small text -->
<article class="card">
<img class="card__image" src="..." alt="..." />
<div class="card__content">
<h3 class="card__title">Article Title</h3>
<p class="card__description">Description text...</p>
</div>
</article>
</div>
<div class="card-container">
<!-- Wide: horizontal, larger text -->
<article class="card">
<img class="card__image" src="..." alt="..." />
<div class="card__content">
<h3 class="card__title">Article Title</h3>
<p class="card__description">Description text...</p>
</div>
</article>
</div>
<div class="card-container">
<!-- Narrow: stacked, small text -->
<article class="card">
<img class="card__image" src="..." alt="..." />
<div class="card__content">
<h3 class="card__title">Article Title</h3>
<p class="card__description">Description text...</p>
</div>
</article>
</div>
</div>Subgrid: Vererbung der Ausrichtung
Subgrid löst das Problem der Kartenraster-Ausrichtung, das Frontend-Entwicklern seit Jahren zu schaffen macht. Enthalten Cards unterschiedlich viel Inhalt, geraten ihre internen Elemente (Titel, Beschreibung, Fußzeile) über die Zeile hinweg aus der Flucht. Subgrid lässt Kindelemente die Spuren (Tracks) des übergeordneten Grids erben.
/* ❌ Without subgrid — card internals don't align across rows */
.product-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.product-card {
display: flex;
flex-direction: column;
}
/* Titles, descriptions, and prices at different heights
depending on content length. Looks messy. */
/* ✅ With subgrid — card internals align perfectly */
.product-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.product-card {
display: grid;
grid-row: span 4; /* image, title, description, price */
grid-template-rows: subgrid;
gap: 0.75rem;
border-radius: 0.75rem;
overflow: hidden;
}
.product-card__image {
aspect-ratio: 16 / 10;
object-fit: cover;
width: 100%;
}
.product-card__title {
font-weight: 600;
padding: 0 1rem;
}
.product-card__description {
color: #666;
font-size: 0.9rem;
padding: 0 1rem;
}
.product-card__price {
font-weight: 700;
font-size: 1.25rem;
padding: 0 1rem 1rem;
align-self: end;
}Jede Card in der Zeile teilt sich dieselben Zeilenspuren. Hat eine Card einen längeren Titel, reservieren alle Cards dieser Zeile denselben Platz für Titel. Beschreibungen richten sich aus. Preise richten sich aus. Das Grid übernimmt das automatisch.
Dashboard-Layouts mit Container Queries
Dashboards sind der ideale Anwendungsfall für Container Queries. Widgets müssen sich an den ihnen zugewiesenen Platz anpassen, der sich dynamisch ändert, wenn Nutzer Panels in der Größe verändern oder Sidebars einklappen.
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
padding: 1rem;
}
.widget {
container-type: inline-size;
container-name: widget;
background: white;
border-radius: 0.75rem;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
/* Compact widget — shows summary only */
@container widget (max-width: 350px) {
.widget__chart {
display: none;
}
.widget__header {
flex-direction: column;
gap: 0.5rem;
}
.widget__value {
font-size: 1.5rem;
}
}
/* Standard widget — shows chart and summary */
@container widget (min-width: 351px) and (max-width: 600px) {
.widget__chart {
height: 150px;
}
.widget__value {
font-size: 2rem;
}
}
/* Expanded widget — full detail view */
@container widget (min-width: 601px) {
.widget__chart {
height: 250px;
}
.widget__details {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.widget__value {
font-size: 2.5rem;
}
}Container Queries und Subgrid kombinieren
Das wahre Potenzial entfaltet sich, wenn Container Queries und Subgrid zusammenwirken. Container Queries übernehmen die Layout-Anpassung, Subgrid übernimmt die Ausrichtung.
.feature-section {
container-type: inline-size;
container-name: features;
}
.feature-grid {
display: grid;
gap: 2rem;
}
/* Single column for narrow containers */
@container features (max-width: 500px) {
.feature-grid {
grid-template-columns: 1fr;
}
}
/* Two columns with subgrid alignment */
@container features (min-width: 501px) and (max-width: 900px) {
.feature-grid {
grid-template-columns: repeat(2, 1fr);
}
.feature-item {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
}
}
/* Three columns for wide containers */
@container features (min-width: 901px) {
.feature-grid {
grid-template-columns: repeat(3, 1fr);
}
.feature-item {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
}
}
.feature-item__icon {
font-size: 2rem;
}
.feature-item__title {
font-size: clamp(1rem, 2.5cqi, 1.25rem);
font-weight: 600;
}
.feature-item__description {
color: #555;
font-size: clamp(0.875rem, 2cqi, 1rem);
align-self: start;
}Style Queries für zustandsbasiertes Styling
Container-Style-Queries ermöglichen es, auf die Werte benutzerdefinierter Eigenschaften eines Containers zu reagieren, und erlauben so zustandsgesteuertes Component-Styling ganz ohne das Umschalten von JavaScript-Klassen.
.theme-section {
container-type: inline-size;
--theme: light;
}
.theme-section[data-theme="dark"] {
--theme: dark;
}
/* Style query responds to custom property */
@container style(--theme: dark) {
.card {
background: #1a1a2e;
color: #eee;
border-color: #333;
}
.card__title {
color: #fff;
}
.card__description {
color: #ccc;
}
}
@container style(--theme: light) {
.card {
background: #fff;
color: #333;
border-color: #e0e0e0;
}
}Die wichtigsten Erkenntnisse
Container Queries und Subgrid verändern grundlegend, wie wir an responsives Design herangehen. Container Queries verlagern die Reaktionsfähigkeit vom Viewport auf die Komponentenebene und machen Komponenten so über verschiedene Layout-Kontexte hinweg wirklich wiederverwendbar. Container-Query-Einheiten (cqi) ermöglichen fließende Typografie und Dimensionierung relativ zum Container der Komponente.
Subgrid löst das Ausrichtungsproblem von Cards, indem es Kindelemente die Spuren des übergeordneten Grids erben lässt. Keine unausgerichteten Titel, Beschreibungen und Preise mehr über Card-Zeilen hinweg. Kombiniert mit Container Queries erhält man Komponenten, die ihr Layout an den verfügbaren Platz anpassen und gleichzeitig ihre internen Elemente an denen ihrer Geschwister ausrichten.
Das sind keine experimentellen Features – sie werden von Browsern breit unterstützt und sind produktionsreif. Jede neue Komponente, die du baust, sollte mit Container Queries beginnen statt mit Media Queries.


