A media query can only ever ask 'how wide is the viewport' — container queries ask the more useful question 'how wide is the space THIS component actually has,' which media queries have never been able to answer.
Advanced
2 min read
The gap media queries always had: a component doesn't know its own container's width
/* A media query can only ever check the VIEWPORT, never a component's actual available space — this card looks identical whether it's the full width of a wide page or squeezed into a narrow sidebar, because the viewport itself hasn't changed size in either case */@media (min-width: 600px) { .card { display: flex; }}
The same .card component might render at very different actual widths depending on where it's placed — full-bleed in a wide main column, or squeezed into a 250px sidebar — but a @media query has no way to know that; it only ever sees the viewport's total width, which is identical in both placements. This is the real, structural gap container queries close: the ability for a component to respond to its own available space, not the page's.
Declaring a container, then querying it
.card-wrapper { container-type: inline-size; /* opts this element in as a queryable container, tracking its own width */ container-name: card; /* optional — names it for clarity when nesting multiple containers */}@container card (min-width: 400px) { .card { display: flex; gap: 16px; } /* applies when THIS card's wrapper is at least 400px wide */}
container-type: inline-size is the opt-in step — without it, an element isn't a queryable container at all, and @container rules targeting it simply never match. Once declared, @container works almost identically to @media syntactically (the same min-width/max-width conditions), but evaluates against the named container's actual current width, not the viewport — the same .card component now genuinely adapts differently depending on whether its wrapper happens to be in a wide column or a narrow sidebar.
Why this genuinely changes how reusable components get built
Before container queries, a component meant to be reused in genuinely different layout contexts (a card that appears both in a 3-column grid and a narrow sidebar) had no CSS-only way to adapt to each context — the common workarounds were either accepting one compromise layout that worked "well enough" everywhere, or reaching for JavaScript (a ResizeObserver) to measure the container and toggle a class manually. Container queries make the CSS-only version of that adaptation possible for the first time, closing a real, long-standing gap between "build a truly reusable, self-adapting component" and "the CSS language could actually express that."