Articles /
Container queries in 2026
The complete guide to @container — why viewport-based media queries aren't enough.
The problem: media queries break component reuse
You build a card component. It works in the main column. Then someone puts it in a sidebar. Suddenly it's too wide, the title wraps awkwardly, and the three-column grid turns into a mess. You add breakpoint overrides for the sidebar context. Now the card has two different breakpoint sets depending on where it's used.
This is the fundamental problem with media queries: they respond to the viewport, not the component's actual context. Container queries fix this at the source.
How container queries work
You declare a "query container" on a wrapper element. Children can then use @container to apply styles based on the container's size.
/* Step 1: declare the container */
.card-wrapper {
container-type: inline-size;
container-name: cards; /* optional — use for nested containers */
}
/* Step 2: query it from children */
.card-grid {
display: grid;
gap: 1rem;
}
@container cards (min-width: 28rem) {
.card-grid { grid-template-columns: repeat(2, 1fr); }
}
@container cards (min-width: 44rem) {
.card-grid { grid-template-columns: repeat(3, 1fr); }
}
Now put .card-wrapper anywhere — sidebar, main column, modal, full-bleed section — and the card grid adapts to its actual space. No new breakpoints to write.
Container types
- inline-size — queries the inline axis (width in horizontal writing modes). The most common type. Only the inline dimension creates containment.
- size — queries both axes (width and height). Requires explicit height on the container. Use sparingly.
- style — queries custom property values (e.g.
@container style(--variant: compact)). Enables design-system-level conditional styling based on tokens. - scroll-state — queries scroll state (stuck, snapped, overflow). Experimental in 2026.
Container units
Inside a @container query or inside a container, you can use container-relative units:
/* cqi = 1% of container's inline size */
.card h2 { font-size: clamp(0.875rem, 4cqi, 1.25rem); }
/* cqw, cqh, cqmin, cqmax also available */
This lets typography scale relative to the container, not the viewport — combined with clamp(), it gives you truly adaptive components.
Style queries (coming)
Style container queries let you query CSS custom property values, enabling a "props in CSS" pattern:
.button-group {
container-type: style;
}
@container style(--size: compact) {
.button { padding: 0.3rem 0.6rem; font-size: 0.8rem; }
}
@container style(--size: large) {
.button { padding: 0.75rem 1.5rem; font-size: 1rem; }
}
Set --size: compact on a container in CSS or HTML and all children adapt. This is the CSS equivalent of passing a "size" prop in React — without JavaScript.
When to use container queries vs media queries
- Use media queries for page-level layout changes — main column + sidebar, header nav changes, hero section sizing.
- Use container queries for component-level layout — any card, list, form, or widget that's reused in multiple contexts.
- Combine them: media queries for the overall page frame, container queries for what's inside it.