CSS container queries let you style an element based on the size of its own parent container, rather than the size of the entire viewport. You use them by declaring a container-type on a parent element and then writing @container rules that respond to that container’s dimensions. This solves the long-standing problem where components built with only media queries break when placed in a narrow sidebar or a wide hero section on the same page.
Background: Why Container Queries Exist
Before container queries, responsive design relied almost entirely on media queries, which respond to the viewport width. A card component designed for a full-width page would look fine on a desktop monitor but become cramped or overflow when dropped into a 300px sidebar on the same screen. Developers worked around this with complex CSS grid tricks, JavaScript resize observers, or by maintaining multiple component variants. Container queries change the mental model: instead of asking “how wide is the browser?” you ask “how wide is my parent?”. This makes components truly reusable across layouts. The feature shipped in all major browsers in early 2023, following years of development and an earlier, incompatible proposal that was abandoned. The current spec is stable, and browser support is now broadly safe for production use.
How Container Queries Work
Container queries require two parts: a container and a query. First, you designate an element as a container using the container-type property. The most common value is inline-size, which makes the element a query container based on its width only. The other value, size, establishes both width and height containment, but it requires the element to have an explicit size or a size determined by its contents; otherwise it can collapse. You can also name your container with the container-name property or the shorthand container.
.card-wrapper {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
In this example, the .card element switches to a two-column layout only when its parent .card-wrapper is at least 400px wide. The query works exactly like a media query, but it measures the container instead of the viewport. If you omit the container name, the query applies to the nearest ancestor container. You can use min-width, max-width, min-height, and max-height conditions, as well as style queries, which are a separate but related feature that checks computed values like custom properties.
Choosing Between Container Queries and Media Queries
The decision is not either-or; the two features complement each other. Use container queries for component-level responsiveness: cards, navigation bars, product grids, chat bubbles, or any UI piece that must adapt to its placement. Use media queries for page-level layout: the overall grid, the number of columns in a full-page section, typography scale, or spacing that should change based on the device. A common pattern is to use media queries to define the main page structure and container queries to make each component inside that structure adapt independently. For example, a media query might stack a sidebar below the main content on small screens, while a container query inside the sidebar makes its widget switch to a compact layout. This separation keeps your CSS predictable and your components portable.
Common Problems and Misconceptions
The most frequent mistake is applying container-type: size without giving the container a definite size. Because size applies both inline and block size containment, the element’s height collapses to zero unless you set it explicitly, which then breaks the layout. Unless you genuinely need height-based queries, use inline-size. Another common issue is that container queries do not respond to the element’s own size, only to an ancestor container. You cannot query the element itself. Also, the min-width and max-width conditions in container queries refer to the container’s content box size, not the border box, which can cause off-by-a-few-pixels surprises if you have thick borders or padding. Finally, note that container queries do not work on the root element; the viewport is not a container. For viewport-level changes, you still need media queries.
Practical Example: A Responsive Card Component
Consider a product card that should display a vertical layout in narrow containers and a horizontal layout in wider ones. Set the parent grid cell as the container, then write two container queries.
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.product {
container-type: inline-size;
}
.product-card {
display: flex;
flex-direction: column;
}
@container (min-width: 350px) {
.product-card {
flex-direction: row;
align-items: center;
}
.product-card img {
width: 120px;
}
}
Here, the .product element is the container. When the grid column is at least 350px wide, the card switches to a row layout. Because the grid uses auto-fit with a minimum of 250px, the same component automatically adapts whether it appears in a two-column desktop grid or a single-column mobile layout. This is the core benefit: you write the component’s responsive behavior once, and it works wherever you place it.
Container Query Units and Style Queries
Container queries also introduce new units: cqw, cqh, cqi, cqb, cqmin, and cqmax. These work like viewport units but are relative to the nearest container’s dimensions. For example, font-size: 5cqi sets the font size to 5% of the container’s inline size. This is useful for fluid typography inside components. Style queries, a related feature, let you query the computed value of a custom property. For example, you can check @container style(--theme: dark) and apply different styles. Browser support for style queries is still partial and evolving, so check current compatibility before relying on them in production. Container query units, however, are well supported alongside the main feature.
Performance and Browser Support
Container queries are implemented natively in all current versions of Chrome, Edge, Firefox, and Safari. No polyfill is needed for modern browsers. Performance is generally good because the browser only recalculates styles when a container’s size actually changes, similar to how media queries work. However, be cautious with deeply nested containers: a container inside another container can cause multiple style recalculations when the outer one resizes. In practice, this is rarely a problem unless you have dozens of nested query containers. For older browsers, you can provide a fallback using media queries or a JavaScript-based polyfill, but the native implementation is now the standard approach.
Frequently Asked Questions
Can I use container queries with flexbox or grid?
Yes. Container queries work with any layout method. The container itself can be a flex item, a grid item, or a block element. The query responds to the container’s content box size, which is determined by the layout around it. The card example above uses a grid parent and a flex container inside, which is a common and fully supported pattern.
What is the difference between container-type: inline-size and size?
inline-size makes the element a query container based on its width (or inline axis), and it does not apply size containment to the block axis, so the element’s height behaves normally. size applies containment to both axes, which means the element’s height is also contained and can collapse to zero unless explicitly set. Use inline-size unless you specifically need height-based queries.
Do container queries replace media queries?
No. Media queries respond to the viewport, while container queries respond to a parent element. They solve different problems. Media queries are still necessary for page-level layout decisions, such as changing the number of columns in the main grid or adjusting global font sizes. Container queries handle component-level adaptability. Most well-structured sites use both.
Can I use container queries on the html or body element?
No. The root element and the viewport cannot be query containers. If you need to respond to the viewport size, use a media query. Container queries require an actual element that can be measured as a container, and the root element is excluded by the specification.
How do I debug container queries in DevTools?
In Chrome DevTools, the Elements panel shows a badge next to elements that are query containers. Clicking the badge highlights the container and shows its size. You can also inspect the @container rules in the Styles pane, and the tool will indicate whether each rule is currently active. Firefox DevTools has similar support, showing container information in the Rules view.
What happens if no ancestor is a container?
If you write an @container rule and no ancestor is a query container, the rule is ignored entirely. The styles inside it will not apply. This is a common source of confusion: the query silently does nothing. Always verify that at least one ancestor has container-type set.
Related
General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.
More in this bed
- Google Chrome Helper: What It Is & How to Disable
- Fix 0x80070422 on Windows Server (Step-by-Step)
- How to Troubleshoot a Malfunctioning Driver on Windows
- How to Create Folders in Microsoft Outlook
- Fix Status Range List Conflict 0xc0000282 in Windows
- Fix Software Not Uninstalling on Windows 10