Container queries for component-level responsive design
Published December 8, 2026
.card-wrapper {
container: card / inline-size;
}
.card {
display: grid;
gap: 0.5rem;
}
@container card (min-width: 400px) {
.card {
grid-template-columns: auto 1fr;
align-items: center;
}
}What
container: card / inline-size turns .card-wrapper into a named query container. The @container card (min-width: 400px) rule then styles .card based on that container's width, not the browser viewport's.
Why it matters
A media query only ever answers "how wide is the viewport?" That's the wrong question for a reusable component: the same card can sit in a 1200px-wide main column or a 280px sidebar on the exact same page at the exact same viewport width, and a media query has no way to tell those two placements apart. Before container queries, "respond to my container's width" meant either ResizeObserver and JS-toggled classes, or giving up and shipping one layout that's a compromise for every context the component ends up in.
Container queries move that responsiveness into CSS, scoped to wherever the component actually lives, with no JavaScript and no layout-thrashing resize listener.
How it works
container: card / inline-sizeis shorthand forcontainer-name: cardpluscontainer-type: inline-size.inline-sizecontainment means the container is queried by its inline-axis size (width, in horizontal writing modes) — the common case, and cheaper for the browser than fullsizecontainment on both axes.- Naming the container
cardlets@container card (...)target this specific container even if it's nested inside another, unnamed or differently-named container — without a name, an@containerquery matches the nearest any container, which gets ambiguous once containers nest. @container card (min-width: 400px) { .card { ... } }applies its declarations only when.card-wrapper's content-box width is at least 400px — switching the card from a stacked, single-column layout to a two-column one with room to spare.
Gotchas
- An element can't query itself.
container-typehas to be set on an ancestor (.card-wrapperhere), and the@containerrule styles descendants of that ancestor — never the container element itself for size queries. - Setting
container-type: size(rather thaninline-size) applies layout containment on both axes, which affects how the container's own height is computed by its parent — usually not what you want unless you're deliberately giving the container a fixed size some other way. - This CSS block is 13 lines by the repo's line-count rule, past the 6-11 target, hence
lineWaiver: true. Cutting the container declaration or the base.cardlayout would leave a query with nothing meaningful to override.
Related
ResizeObserver— the JS equivalent; still the right tool when the response to a size change is more than styling (e.g. re-measuring text, choosing what content to render).- Media queries — still correct for page-level layout decisions (nav collapse, overall grid) that really are about the viewport, not a specific component.