CSS Container Queries: Patterns and Pitfalls
Container queries have been usable for a few years, yet adoption lags behind awareness. The State of CSS survey figures quoted in recent write-ups put awareness at around 86 percent of developers but actual use at roughly 41 percent. Part of the gap is habit: people reach for @container as if it were another @media, hit a wall, and go back. This article walks through the mental model, a minimal working pattern and the traps that cause most of the frustration.
Two different questions
A media query asks about the viewport: how wide is the window, does the user prefer dark mode, is this a touch device. A container query asks about the space a component has been given by its parent. That makes media queries the right tool for page-level structure, such as the main grid or a top navigation bar, and container queries the right tool for components that appear in different places, such as a product card that sits in a wide grid on one page and a narrow sidebar on another.
Recent commentary suggests treating them as complements rather than replacements. One 2026 Smashing Magazine piece describes it as macro layout versus micro layout, and cites roughly 94 percent browser support for size queries, so the feature is safe to use in production for the basic case.
A minimal pattern
The parent must opt in to being measured. Without that, the browser does not track its size, and nothing inside can query it.
.card-slot {
container: card / inline-size;
}
.card {
display: grid;
gap: 0.75rem;
}
@container card (min-width: 28rem) {
.card {
grid-template-columns: 9rem 1fr;
align-items: start;
}
}
The shorthand names the container card and makes it measure its inline size. Naming is optional, but it keeps your rules stable when someone later wraps the component in another container. The card switches to a two-column layout whenever its slot is wide enough, regardless of how wide the window is.
Sizing with container units
Container query units let typography and spacing scale with the slot instead of the screen. The logical variants cqi and cqb follow writing direction and are generally preferable to cqw and cqh.
.card h3 {
font-size: clamp(1rem, 0.6rem + 2.5cqi, 1.75rem);
}
If no ancestor is a query container, these units fall back to viewport-based values, so the declaration does not break; it just behaves like viewport units until a container exists.
The traps that catch people
A component cannot query itself
The element that is the container cannot also be restyled by its own query, because its size would depend on its own result. In practice you need a wrapper: the wrapper is the container, the component inside responds to it. This is the most common reason a first attempt appears to do nothing.
Be careful with size
Setting container-type: size asks the browser to ignore children when working out block size. Unless the element has a declared height, a minimum height or an aspect ratio, it can collapse to nothing. Prefer inline-size unless you truly need to query height.
Custom properties do not work in conditions
Writing something like (min-width: var(--bp-md)) inside an @container rule is ignored, because custom properties cascade down the tree and could otherwise feed back into the very query that reads them. Use literal values, or generate them in a preprocessor.
Grid and flex items need an extra layer
Making a grid item itself the container is a common source of odd results. Add an inner wrapper and designate that as the container. Flex items without a defined size can also collapse, so give them a basis or an intrinsic size.
Do not wrap the root
Querying the document root causes awkward behaviour. Attach containers to regions such as main, a sidebar, or the slot that holds a component.
What is not ready yet
Size queries and container units are well supported. Style queries are another matter: querying custom properties as flags was awaiting Firefox support as of the LogRocket article updated in March 2026, and the broader form of style queries has no support at all. Scroll-state queries, which let you style a sticky element differently once it is stuck, work in Chromium-based browsers only. If you use them, wrap them in a feature query and treat the effect as a progressive enhancement:
@supports (container-type: scroll-state) {
.header-wrap {
position: sticky;
top: 0;
container-type: scroll-state;
}
@container scroll-state(stuck: top) {
.site-header {
box-shadow: 0 2px 8px rgb(0 0 0 / 0.15);
}
}
}
Accessibility and debugging
Layout changes driven by a container should never reorder content in a way that breaks the logical tab sequence or reading order. Both Chrome and Firefox DevTools mark container elements in the Elements panel, and hovering the badge highlights the container on the page, which is the fastest way to see which ancestor is actually being measured.
For component-heavy work such as theme sections and reusable blocks, container queries remove a lot of viewport guesswork. If you are planning a redesign around reusable components, our web development services include this kind of front-end restructuring, and our Shopify themes show the component-first approach in practice.