I have one Card component that gets reused in three very different contexts: a narrow sidebar, a three-column grid on the homepage, and a full-width modal. For years the only tool for "make this layout respond to its available space" was a media query, which responds to the viewport, not the component's actual container. That mismatch caused constant one-off overrides.
The Media Query Problem
A media query can tell you the browser window is wide. It can't tell you that a specific card happens to be squeezed into a 240px sidebar on that same wide screen. So the old CSS ended up full of context-specific overrides:
.sidebar .card { flex-direction: column; }
.grid .card { flex-direction: row; }
@media (max-width: 480px) {
.grid .card { flex-direction: column; }
}
Every new place the card got used needed its own override, and the override logic had nothing to do with the card's own size — it was really guessing at layout context by proxy.
Querying the Container Instead
Container queries let the component respond to the size of its actual parent, regardless of where that parent sits on the page. First you mark a container:
.card-slot {
container-type: inline-size;
container-name: card-slot;
}
Then the card itself queries that container directly, not the viewport:
.card {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
@container card-slot (min-width: 320px) {
.card {
flex-direction: row;
align-items: center;
}
}
@container card-slot (min-width: 560px) {
.card {
gap: 1.5rem;
}
.card-thumbnail {
width: 160px;
}
}
Now the exact same .card markup automatically stacks vertically in the narrow sidebar, lays out horizontally once its slot passes 320px, and gets extra breathing room in the wide modal — with zero JavaScript and zero knowledge of where it's being rendered. All three of the contexts I mentioned use the identical component now; only the surrounding card-slot width differs.
Container Query Units
The other piece that removed a lot of fiddly math was container query length units — cqw, cqh, cqi — which are percentages of the container's size rather than the viewport's:
.card-title {
font-size: clamp(0.95rem, 4cqw, 1.25rem);
}
That single line replaced three separate font-size overrides for three separate containers, because the title now just scales with however much horizontal room its own slot actually has.
What I'd Warn People About
Support is solid in current evergreen browsers, but if you need to support anything meaningfully older, check your actual analytics before committing to container queries as the only layout mechanism — a media-query fallback for very old browsers is still reasonable for critical layouts. The other adjustment is mental: it's easy to reach for container queries everywhere once you have them, but a lot of layout still doesn't need them. I only reach for them now when a component genuinely has to behave differently at different sizes independent of the viewport — which, once you notice it, turns out to be more often than I expected.