Container queries have been the most-requested CSS feature for over a decade. Media queries answer "how wide is the viewport?" — but components don't care about the viewport. They care about the space they're placed in. Container queries finally answer the right question.
Browser support hit baseline in 2024. In 2026 there's no reason not to use them. Let's look at exactly what they unlock and how to migrate today.
The Problem with Media Queries
Consider a ProductCard component. In a sidebar it gets 200px of space. In a main grid it gets 400px. In a hero it gets 800px. A single @media query on the viewport breakpoint can't express this—the card is the same viewport width in all three contexts.
The workaround was BEM modifier classes (.card--wide, .card--narrow), JavaScript resize observers, or just accepting inelegant fixed layouts. All of these are kludges. Container queries are the proper solution.
Container Query Syntax
/* 1. Define a containment context */
.card-wrapper {
container-type: inline-size;
container-name: card; /* optional — for named queries */
}
/* 2. Write queries relative to the container */
.product-card {
display: flex;
flex-direction: column;
gap: 1rem;
}
/* When the containing .card-wrapper is >= 400px wide */
@container card (min-width: 400px) {
.product-card {
flex-direction: row;
align-items: center;
}
.product-card__image {
width: 180px;
flex-shrink: 0;
}
}
@container card (min-width: 640px) {
.product-card {
padding: 2rem;
}
.product-card__price {
font-size: 1.5rem;
}
}
You can nest containers. A card inside a sidebar inside a modal — each level can have its own containment context.
Practical Examples
1. Fluid Typography Without JavaScript
.article-body { container-type: inline-size; }
@container (min-width: 480px) {
.article-body p {
font-size: 1.0625rem;
line-height: 1.9;
}
}
@container (min-width: 720px) {
.article-body p {
font-size: 1.125rem;
column-count: 2;
column-gap: 2rem;
}
}
2. Navigation That Adapts to Its Container
.nav-wrapper { container-type: inline-size; }
.nav { display: flex; gap: .5rem; }
@container (max-width: 320px) {
.nav { flex-direction: column; }
.nav-label { display: none; } /* icon only */
}
Style Queries (2026)
Beyond size, modern browsers support style queries — querying the computed CSS custom property value of the container. This enables theme propagation without class toggling.
/* Set a custom property on the container */
.dark-section { --color-scheme: dark; }
/* Children query it */
@container style(--color-scheme: dark) {
.card {
background: #111;
color: #f5f5f5;
border-color: rgba(255,255,255,.1);
}
}
Migration Guide
- Step 1: Add
container-type: inline-sizeto layout wrappers (grid cells, sidebar slots, card parents) - Step 2: Replace layout-specific BEM modifiers with
@containerrules on the component - Step 3: Remove JavaScript resize observers used for layout switching — they're now unnecessary
- Step 4: For polyfill support (only needed for Safari < 16) use
container-query-polyfill— ~8KB gzipped
96%
Browser support 2026
0 JS
Needed for layout
40%
Less CSS in practice
Summary
- Add
container-type: inline-sizeto any element whose children should react to its size - Write
@containerrules inside component CSS — no viewport knowledge needed - Style queries enable theme propagation without class toggling or JS
- Replace JavaScript resize observers and BEM modifier patterns
- Browser support is 96%+ — ship today, polyfill if Safari 15 matters