Container Queries
Components that respond to their container, not the viewport.
For twenty years, "responsive design" meant "respond to the viewport." That was always a hack. You don't want your card to know how big the browser is. You want it to know how big itis. A 320px-wide card should look the same in a sidebar as it does on a phone, no matter what the viewport says. That's what container queries are for, and they finally shipped in every evergreen browser by 2023.
The setup: declare a container
Container queries don't come for free. You have to mark an element as a containment context by giving it container-type. The two common values:
inline-size: contain in the inline dimension (width, for left-to-right languages). 95% of the time, this is what you want.size: contain in both dimensions. Rarely needed and has more layout side effects.
.card-wrapper {
container-type: inline-size;
}
/* Now any descendant can query the wrapper's width */
@container (min-width: 400px) {
.card { display: flex; gap: 16px; }
}
@container (max-width: 399px) {
.card { display: block; }
}Named containers for clarity
If you have nested containers and need to query a specific ancestor, give it a name with container-name:
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* Or the shorthand */
.card-wrapper { container: card / inline-size; }
@container card (min-width: 400px) {
.card { /* ... */ }
}When container queries beat media queries
Imagine you build a product card. On the homepage it's in a three-column grid: narrow. In the cart it's a full-width list item: wide. With media queries, you'd need to know the layout context and write different rules. With container queries, the card adapts to whatever space it's given. The same component code works everywhere.
cqi, cqw, cqh: container-relative units
Container queries also added new units that scale with the container, not the viewport. Most useful:
cqi: 1% of the container's inline size (width).cqb: 1% of the container's block size (height).cqw,cqh: same as the above but tied to width/height specifically.
Combine with clamp() and you get fluid typography that scales with the component, not the viewport:
.card h3 {
/* font sizes with the card, not the page */
font-size: clamp(1rem, 4cqi, 1.5rem);
}A card that adapts to its container
This card has two layouts: a stacked version for narrow containers and a horizontal version when there is room. Drag the container widths around in the HTML by editing the wrapper styles, or just resize the preview pane.
container-type: inline-sizeintroduces layout containment, which is what makes container queries possible. The browser has to lay out the container before its children. This is usually free, but in deeply nested grids it can cost. Don't putcontainer-typeon every element "just in case." Add it where you need it.Container queries work great with components
The killer use case is design systems. A Card component ships with its own container queries built in. Drop it into any layout (sidebar, modal, three-column grid, full bleed) and it reformats itself. You don't have to pass prop variants like compact={true} from the outside. The component figures it out from context.
Style queries (preview)
There's a sibling feature called style queries for querying CSS custom properties (e.g., "if the--themevalue is dark, do this"). It's rolling out in 2025-2026. Not stable enough to bet a product on yet, but worth knowing about for the future:
@container style(--theme: dark) {
.card { background: #0b1020; color: #e2e8f0; }
}Quiz
Before you can query a container's size with @container, what must you do?
Recap
- Container queries respond to a parent's size, not the viewport. Components become layout-agnostic.
- Opt in with
container-type: inline-size. Name withcontainer-namewhen you have nesting. - Query with
@container (min-width: 400px) { ... }. cqiand friends are container-relative units. Combine withclamp()for component-fluid typography.- Media queries are still right for layout-wide decisions; container queries are right for component-level ones.