Container queries respond to a component’s own space, not the viewport
Aliases: container query · @container · available inline size
What it is
Same viewport: a 300 px rail, a 900 px main. A media-object component that only listens to viewport breakpoints becomes “desktop: image on the left” in both. In the rail there are only 300 px; image-left kills the type. A container query measures the width the component actually received, so the rail copy can stack and the main copy can stay row-wise. Viewport breakpoints cannot see how much is left after the split.
Choosing viewport failure widths, and staying usable between them, is the shell’s job. The component is holding a different ruler: its parent container.
Why it happens
@media reads the window. A component does not know which slice of that window it was given — rail, split view, grid cell all shatter the viewport. A container query reads the inner size of the nearest query container, which is the space the component can actually use. In one frame, one component class can sit at two container widths, therefore in two inner layouts.
That is not copying viewport breakpoints onto the component. Four 280 px cells at a 1200 viewport are still “narrow” to the component, not “desktop.”
Where it stops holding
Engines without container queries fall back to viewport queries or a width passed from the parent; behaviour will fork, and you live with the downgrade. The page shell (sidebar or not, hamburger or not) should still watch the viewport; that is window-level IA. If the root container is the viewport, the container query collapses to a media query and buys nothing.
Height container queries are rarer and can cycle with content height; be careful.
Applying it
- Put container queries on components that will be dropped into different slots. Query at the width where their internals break, not at a habitual 768.
- Leave page-level media queries to the shell: nav shape, pane count. Do not restyle an inner card’s image/text structure from a viewport query.
- How to check: on one page, drop the component into a narrow rail and a wide main. If both twins look the same (both “desktop” or both “phone”), it is listening to the viewport. Rail stacked, main in a row: it is listening to the container. Then drag a split-view sash — container width changes, window does not — and the component should follow.
Related
- Same group: F2.15.2 One component can reuse different layouts at different container widths · F2.15.3 Component-level response can evolve without the page breakpoint system · F2.15.4 Too many container breakpoints make the component unpredictable
- Nearby: F2.10 Responsive breakpoints · F2.11 Fluid and adaptive layout · F2.08 Card layout
- Search terms:
container query·@container·available space·viewport media