Container queries and media queries solve different responsive design problems. This guide gives you a practical way to choose between them, reusable CSS patterns, fallback options, and a checklist for checking browser and framework support before changing a component.
Overview
A media query responds to a condition related to the browser viewport, such as its width, height, orientation, or preferred color scheme. It is the right tool when the page-level layout should change because the available screen or device context has changed.
A container query responds to the size or style of an ancestor container. It is useful when a component must adapt to the space assigned to it, regardless of where that component appears. The same card can use a compact layout in a narrow sidebar and a horizontal layout in a wide content column without relying on the overall viewport width.
The simplest decision rule is:
- Use a media query for page shell decisions: navigation, global columns, application chrome, and viewport-level spacing.
- Use a container query for reusable components: cards, panels, widgets, forms, and grid items that can appear in different parent layouts.
- Use both when the page shell and the component have separate responsive responsibilities.
Container queries do not replace media queries. They reduce the coupling between a component and the viewport, which is especially valuable in design systems and component libraries.
Checklist by scenario
Choose a media query for the page shell
Start with a media query when the breakpoint describes the browser window rather than a particular component. Typical examples include collapsing a site header, changing a two-column page into a single column, or reducing global page padding.
:root {
--page-gutter: 1.5rem;
}
@media (max-width: 48rem) {
:root {
--page-gutter: 1rem;
}
.site-navigation {
display: none;
}
.page-layout {
grid-template-columns: 1fr;
}
}
Before adding a viewport breakpoint, ask whether the change should happen for every component at the same browser width. If the answer is no, a container query is often a better fit.
Choose a container query for reusable components
Use a container query when the component may be placed in multiple contexts. First, define the ancestor as a query container with container-type. Then query the available inline size.
.card-list {
container-type: inline-size;
}
.card {
display: grid;
gap: 1rem;
}
@container (min-width: 36rem) {
.card {
grid-template-columns: 12rem 1fr;
align-items: center;
}
}
The inline-size value tracks the container's logical inline dimension, which is generally the horizontal dimension in common left-to-right writing modes. It is a useful default when a component should respond to its available line length rather than a physical width.
Use a named container when several ancestors exist
Named containers make intent clearer and help prevent a component from responding to the wrong ancestor.
.content-column {
container: article / inline-size;
}
@container article (min-width: 42rem) {
.feature-panel {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
Use a name when nesting is complex, when a component is shared across teams, or when a nearby ancestor might later become a query container. Choose names based on layout responsibility, such as sidebar, article, or dashboard, rather than implementation details.
Use both for independent layers of responsiveness
A dashboard can use a media query to change the overall page grid and a container query to change each dashboard panel. This separation prevents panel CSS from assuming that the viewport and panel widths are always related.
.dashboard {
container-type: inline-size;
display: grid;
grid-template-columns: 1fr;
}
@media (min-width: 64rem) {
.dashboard {
grid-template-columns: 18rem 1fr;
}
}
@container (min-width: 40rem) {
.dashboard-panel__body {
grid-template-columns: 1fr 1fr;
}
}
Use style queries selectively
Size queries are the most familiar container-query pattern. Style queries can respond to a custom property or another supported style condition on an ancestor, allowing a component to vary by theme or semantic mode rather than physical size. Because syntax and support can vary more than for common size-query patterns, verify the target browsers and tooling before making style queries a required part of a critical interface.
.panel-region {
--panel-tone: neutral;
container-type: inline-size;
}
@container style(--panel-tone: emphasis) {
.panel {
border-color: currentColor;
}
}
What to double-check
| Feature | What it responds to | Implementation check |
|---|---|---|
| Size query | An ancestor's available dimensions | Confirm the ancestor has an appropriate container-type or container declaration. |
| Inline-size query | The logical inline dimension of a container | Prefer it for writing-mode-aware component layouts and test narrow, medium, and wide placements. |
| Style query | A supported style or custom-property condition | Check current browser compatibility, syntax support, and whether your CSS build process preserves the rule. |
When checking CSS browser support, test the exact feature you plan to use rather than treating all container queries as one capability. A project may support ordinary size queries while still requiring a fallback or progressive enhancement approach for a less common style-query pattern.
- Inspect the computed styles and confirm that the intended ancestor is a query container.
- Check whether an intermediate wrapper changes the container being queried.
- Test the component in its narrowest real placement, not only at common viewport widths.
- Resize the parent independently of the viewport when using browser developer tools.
- Confirm that content still works when the query rule is ignored.
- Review logical properties, writing modes, and text expansion if the component is internationalized.
A useful fallback is to keep the base component usable and layer the container query on top. For example, a card can remain a vertical block by default, then become a two-column layout only when the container is wide enough. This is usually safer than making the queried layout the only valid presentation.
Common mistakes
- Querying without defining a container: A descendant cannot respond to the intended ancestor unless that ancestor establishes the relevant containment.
- Using viewport breakpoints for every component: A viewport width does not tell you how much space a nested component actually has.
- Choosing breakpoints from habit: Select a threshold where the content needs a layout change. A card with a long title may need more room than a card with a short label.
- Ignoring containment side effects: Container-related properties can affect sizing, layout, or painting behavior. Test intrinsic sizing, overflow, positioned elements, and sticky elements around the new container.
- Assuming a framework changes CSS behavior: React, Vue, Web Components, and server-rendered templates can all render container-query CSS, but wrappers introduced by a component abstraction may change which element is queried.
- Overusing style queries: A custom property can communicate a mode, but it should not become an opaque substitute for clear component variants.
- Testing only one viewport: A page can look correct at desktop and mobile widths while failing when a sidebar, modal, or grid track gives the component an unexpected intermediate width.
When to revisit
Revisit this decision when a component moves into a new layout, a design-system wrapper changes, or a responsive regression appears at an intermediate width. These are signals that the component may be coupled to the viewport when it should be coupled to its container.
Before a major planning or release cycle, run this short review:
- List components that appear in more than one parent layout.
- Mark which responsive rules currently depend on viewport width.
- Convert one representative component to a container-based base-plus-enhancement pattern.
- Test size, inline-size, and any style-query syntax against the browsers and CSS tooling your project supports.
- Compare the result at real parent widths, including narrow sidebars, wide content areas, dialogs, and grid cells.
- Document the chosen container name, threshold rationale, and fallback behavior beside the component.
Use media queries for global composition, container queries for component behavior, and both when those responsibilities are genuinely separate. That rule remains useful as layouts, frameworks, and browser support evolve because it is based on the source of the constraint: the viewport or the component's available space.