// LOADING
// LOADING
// LOADING_ARTICLE
For years, responsive design meant writing breakpoints against the viewport. @media (min-width: 768px) is how most of us learned to adapt layouts. That model works fine when a component always lives at the top level, but it breaks down the moment you start composing UIs out of reusable components. A card that looks great in a wide sidebar needs to look just as good in a narrow drawer — and viewport width tells you nothing about how much space the card actually has.
Container queries solve exactly this problem. They let you write styles that respond to the size of a parent element rather than the viewport.
Before you can query a container, you need to establish one. You do that with container-type.
css.card-wrapper { container-type: inline-size; container-name: card; }
inline-size means "track the inline dimension" (width in horizontal writing modes). You can also use size to track both dimensions, but inline-size is the right default for most layout work. The container-name is optional but useful when you have nested containers and need to target a specific ancestor.
Once the container context is declared, child elements can query it:
css.card { display: flex; flex-direction: column; } @container card (min-width: 400px) { .card { flex-direction: row; } .card__image { width: 40%; } }
The syntax mirrors @media almost exactly. The key difference is that 400px refers to the container's width, not the viewport's.
The old approach to responsive components was to pass a prop or use a resize observer to conditionally apply a class. Something like <Card layout="horizontal" /> when the parent was wide enough, determined by JavaScript. Container queries move this logic entirely to CSS, where it belongs.
This has a direct impact on design systems. If you're working on reusable UI like a portfolio or a component library (see /projects for examples of this in practice), you can now ship components that are truly context-agnostic. Drop the same <Card> into a three-column grid or a single-column feed and it handles both without any prop changes.
If you've wrestled with CSS Grid vs Flexbox for layout decisions, container queries fit naturally into both systems. The containment context lives on the grid item or flex child, and the component inside responds accordingly.
Container queries introduce new relative units:
cqw — 1% of the container's widthcqh — 1% of the container's heightcqi — 1% of the container's inline sizecqb — 1% of the container's block sizecqmin / cqmax — the smaller or larger of cqi and cqbThese are useful for fluid typography inside containers:
css@container card (min-width: 300px) { .card__title { font-size: clamp(1rem, 4cqi, 1.5rem); } }
This scales the title font relative to the card container's width, not the viewport — a much tighter relationship between layout and typography.
Browser support has expanded to include style queries, a related feature that lets you respond to the computed value of a custom property on a container:
css.theme-wrapper { container-type: style; --theme: dark; } @container style(--theme: dark) { .card { background: #1a1a2e; color: #e0e0e0; } }
This is powerful for theming systems where variants are driven by data rather than class names. It's still gaining browser traction, so check support before shipping it in production.
Container queries do not replace media queries — they complement them. You still reach for @media for page-level layout: how many columns the grid has, whether the sidebar is visible, font-size base scaling at small viewports. Then within each layout region, container queries handle component-level adaptation.
A common pattern:
css/* Page-level: media query decides column count */ @media (min-width: 960px) { .layout { grid-template-columns: 1fr 300px; } } /* Component-level: container query adapts the card */ .card-wrapper { container-type: inline-size; } @container (min-width: 420px) { .card { flex-direction: row; } }
This separation of concerns makes the CSS easier to maintain and reason about. The media query owns the skeleton; the container query owns the flesh.
Container queries (container-type, @container size queries) are supported in all modern browsers as of 2023. If you need to support older environments, the @supports rule gives you a clean fallback path:
css.card { /* default layout */ flex-direction: column; } @supports (container-type: inline-size) { .card-wrapper { container-type: inline-size; } @container (min-width: 400px) { .card { flex-direction: row; } } }
For most production projects targeting modern browsers, you can use container queries without a polyfill today.
A few things to keep in mind as you adopt container queries:
container-type on the wrapper, not on the component element itself. The queried container must be an ancestor.container-type: inline-size is the lowest-cost option. Avoid size unless you genuinely need to query height.container-name) prevent confusion in deeply nested structures. If you have a card inside a sidebar inside a layout, naming each container makes the query targets unambiguous.For a deeper look at how these layout techniques fit into a full performance-first approach, Core Web Vitals in 2026 covers how layout shifts interact with CLS scores — something container queries can help or hurt depending on how you use them.
Container queries close a gap that has existed in CSS for a long time. Building components that are truly responsive to their context — not the viewport — makes design systems more composable and reduces the JavaScript you need to bridge the gap. The syntax is intuitive, browser support is solid, and the upgrade from a media-query-only approach is incremental. If you're building or maintaining a component library today, container queries should be part of your toolkit.