CSS container queries and media queries solve different responsive-design problems. This guide gives you a practical way to choose between them, combine them safely, and test reusable components across viewport and container sizes.
Overview
A media query responds to the viewport or another page-level condition. A container query responds to the size or style of an element’s containing block. That distinction matters when a component can appear in several contexts, such as a card shown in a full-width grid, a narrow sidebar, or a modal.
Use a media query when the page itself needs to change: the main navigation collapses, the number of page columns changes, or global spacing is adjusted. Use a container query when a component should adapt to the space it actually receives, regardless of where it is placed.
| Question | Prefer a media query | Prefer a container query |
|---|---|---|
| What controls the change? | Viewport or device-level conditions | Available space inside a component’s container |
| Where is it useful? | Page layout, navigation, global typography | Reusable cards, panels, widgets, and nested layouts |
| What does it improve? | Consistent site-wide breakpoints | Component portability and local responsiveness |
| What must you define? | Usually a viewport breakpoint | A query container on an ancestor |
Container queries are not a replacement for media queries. A robust responsive system often uses both: media queries for the page shell and container queries for components inside that shell.
Checklist by scenario
1. Responsive cards
Choose a container query when the same card needs to work in different parent layouts. First, designate the card’s immediate layout context as a query container:
.card-list {
container-type: inline-size;
}
.card {
display: grid;
gap: 1rem;
}
@container (min-width: 36rem) {
.card {
grid-template-columns: 8rem 1fr;
align-items: start;
}
}
The component changes when its container reaches the threshold, not when the browser window reaches it. Keep the threshold based on the card’s usable content width. If the image, heading, or actions become cramped before the query activates, adjust the component’s internal design rather than choosing a familiar device breakpoint.
2. Page navigation and application chrome
Use a media query for a site-wide header or primary navigation when its behavior is tied to the viewport. For example, a navigation bar may switch from horizontal links to a menu button as the page becomes narrow:
.site-nav__links {
display: flex;
gap: 1rem;
}
@media (max-width: 48rem) {
.site-nav__links {
display: none;
}
.site-nav__toggle {
display: inline-flex;
}
}
A container query can be useful when the navigation is a portable component embedded in a dashboard, shell, or constrained panel. Decide based on ownership: if the page controls the navigation’s space, a media query is often clearer; if the component is placed by many parent layouts, a container query is more resilient.
3. Responsive grids
Use grid’s intrinsic sizing when possible, then add a container query only when the grid’s children need a distinct presentation. This avoids unnecessary breakpoints:
.results {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
gap: 1rem;
container-type: inline-size;
}
@container (min-width: 50rem) {
.results .result-card {
grid-template-columns: 10rem 1fr;
}
}
Check both levels separately. The grid determines how many items fit; the card determines how each item is presented. Keeping those responsibilities distinct makes nested layouts easier to debug.
4. Nested components
For nested layouts, give each component a clear container owner. A child query should respond to the nearest relevant ancestor, not accidentally to an outer page wrapper. Use descriptive container names when several query contexts exist:
.dashboard-panel {
container: panel / inline-size;
}
@container panel (min-width: 40rem) {
.dashboard-panel__content {
grid-template-columns: 1fr 1fr;
}
}
Before adding a nested query, confirm that the child’s behavior is genuinely local. If every instance follows the same page-level rule, a media query or shared layout utility may be simpler.
5. Style-driven variations
Container query syntax can also support style-based conditions in environments that implement the relevant feature. This can be useful when a component responds to a custom property or theme choice rather than available width. Treat style queries as an enhancement: verify the syntax in your supported browser matrix, provide a sensible default, and avoid making essential content inaccessible when the condition is not applied.
What to double-check
- Container establishment: Confirm that the ancestor has the required
container-typeorcontainerdeclaration. A query will not behave as expected if no suitable query container exists. - Inline size versus block size: Most component layouts need
inline-sizebecause the available horizontal space determines the design. Use broader containment only when the component’s requirements justify it. - Query thresholds: Select thresholds from content requirements, not device labels. Test just below and just above every threshold.
- Fallback behavior: The base rule should remain usable if a container query is ignored. A stacked card is often a good default, with the wider arrangement layered on progressively.
- Overflow and intrinsic sizing: Check long headings, translated text, large controls, images without fixed dimensions, and unusually narrow columns. Container queries can expose problems that a viewport-only test misses.
- Accessibility: Responsive changes must preserve reading order, keyboard access, visible focus, sufficient target size, and meaningful labels. Do not use CSS alone to create a different logical order from the document structure.
- Framework boundaries: In component frameworks, decide which element owns the query container and document that contract. Avoid coupling a component to an undocumented wrapper generated by a layout component.
- Browser support: Check the browsers your project actually supports before relying on newer container or style-query features. Use progressive enhancement rather than assuming that a locally working feature is universal.
For a repeatable workflow, inspect the component at its smallest supported width, its transition widths, and several ordinary desktop and mobile widths. Browser developer tools that visualize grid, flex, and container boundaries can make the source of a query much easier to identify.
Common mistakes
Using viewport breakpoints for every component
A viewport breakpoint can appear correct in a page mockup while failing when the component moves into a sidebar or split view. If the component’s available width is the real input, use a container query or an intrinsic layout technique.
Adding a container query without a container
Writing @container rules is not enough. The component needs an ancestor that establishes the relevant query context. Treat the container declaration as part of the component’s layout contract.
Duplicating page and component rules
Do not maintain a media query and a container query that make the same component change for unrelated reasons unless the distinction is intentional. Duplicate rules increase the chance of conflicting declarations and make future breakpoint changes harder to reason about.
Testing only the viewport
Resizing the browser window does not test every container width. Place the component in a narrow column, a wide column, a modal, and any repeated list or grid where it will be used. Also test zoom and increased text size, which can create effective narrow layouts without a narrow viewport.
Reordering content visually
Responsive CSS should not conceal essential content or create a confusing keyboard sequence. Prefer a logical HTML order that remains understandable when layout rules change.
When to revisit
Revisit this decision whenever a component is moved into a new layout, a design system introduces a new wrapper, or a page gains a sidebar, split pane, modal, or embedded view. Those changes alter the component’s available space even when the viewport breakpoints remain unchanged.
Also review the implementation when your browser support policy changes, when you adopt a new framework or CSS build pipeline, or when container and style-query features become more broadly available in your supported environments. Verify syntax and fallback behavior rather than removing a fallback solely because a feature works in one development browser.
Before shipping a responsive component, run this short checklist:
- Identify whether the behavior depends on the viewport, the component’s container, or a style condition.
- Choose the simplest mechanism: intrinsic layout first, then a media or container query where a real condition exists.
- Define and name the query container if the component owns that responsibility.
- Test narrow, wide, and threshold-adjacent container sizes in more than one parent layout.
- Check long content, zoom, keyboard navigation, focus visibility, and reading order.
- Confirm the base experience and fallback remain usable in the supported browser set.
- Record the reason for each threshold so a future change can be made from content evidence rather than habit.
The practical rule is simple: use media queries to coordinate the page, and container queries to make reusable components aware of their own space. When neither requires a breakpoint, let CSS grid, flexbox, and intrinsic sizing do the work.