Debugging Container Queries in DevTools: Why a Rule Doesn't Match
Media queries fail in one way: the viewport is not the size you thought. Container queries have more moving parts — which ancestor is the container, whether it has the right type, whether its name matches, how big it actually is — and each part fails silently. The @container rule is simply never applied, with no error. The narrow problem this page solves is diagnosing that silence quickly, with a checklist that maps each symptom to its cause and the DevTools features in Chrome, Firefox and Safari that reveal it. It belongs to Container Query Syntax Basics in the Mastering Container Queries & Responsive Layouts guide.
Why container queries fail silently
A container query is evaluated in three stages. First, the browser searches ancestors of the styled element for a query container: an element with a container-type other than normal, and a container-name matching the rule's name if the rule has one. Second, it measures that container's content box. Third, it evaluates the condition against the measurement. A failure at any stage makes the rule inapplicable, and CSS has no way to report that except by not applying styles.
Knowing which stage failed narrows the search immediately. The workflow below checks them in order.
The debugging workflow
The sample below contains four deliberate bugs, one per common cause. Each fix is annotated.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Container query bugs</title>
<style>
/* BUG 1: querying yourself. .card is the container AND the element
being styled, so the rule looks for a container ABOVE .card and
finds none. FIX: style a child, or make the parent the container. */
.card { container-type: inline-size; }
@container (width > 30rem) { .card { display: flex; } } /* never applies */
@container (width > 30rem) { .card__body { display: flex; } } /* works */
/* BUG 2: name mismatch. The rule asks for "sidebar"; the ancestor is
named "aside". FIX: use the same name, or drop the name. */
.aside { container: aside / inline-size; }
@container sidebar (width > 20rem) { .nav { columns: 2; } } /* never applies */
/* BUG 3: height query on an inline-size container. Only size
containers can be queried on height. FIX: container-type: size
plus an explicit height, or query width instead. */
.tile { container-type: inline-size; }
@container (height > 10rem) { .tile__meta { display: block; } } /* never applies */
/* BUG 4: collapsed container. A container is a flex item with no
basis, so its content-derived width is 0 and nothing matches.
FIX: give it flex: 1, a width, or align-self: stretch. */
.row { display: flex; }
.row > .widget { container-type: inline-size; } /* 0px wide */
.row > .widget { flex: 1; } /* fixed */
</style>
</head>
<body>
<article class="card"><div class="card__body">Body</div></article>
</body>
</html>
Step 1: confirm the rule exists and is unmatched. Select the element you expected to change. In the Styles pane, an @container rule that is not applying is listed but greyed out or absent from the matched rules, depending on the browser. If the rule is not listed at all, the problem is the selector, not the container.
Step 2: find the container the rule resolved against. In Chrome and Edge, each @container rule in the Styles pane shows the container it resolved to, such as @container (width > 30rem) followed by div.card-slot. Hovering highlights the container on the page; clicking selects it in the Elements tree. If it says no container was found, you are in stage one: check container-type on the intended ancestor, the name, and whether you are styling the container itself.
Step 3: read the container's size. With the container selected, check the Computed pane or the box model diagram. The query compares against the content box — width minus padding and border. A container that looks 400 pixels wide with 24 pixels of padding each side is 352 pixels for query purposes. A reported width of zero means the container has collapsed.
Step 4: check the condition. Copy the condition into a scratch rule on the container itself as an @supports-style sanity check: is it well-formed, are and and or grouped with parentheses, and does it use units you expect? In container conditions em resolves against the container's font size, not the styled element's, which surprises people using em-based thresholds.
The key technique: DevTools badges and overlays
Every major browser now marks containers in the Elements panel, which is the fastest way to see the containment structure of a page at a glance.
In Chrome and Edge, elements that establish a container show a container badge in the Elements tree; clicking it toggles an overlay that outlines the container and labels its size. Firefox's inspector shows the container type in the rules view and marks container query rules with the condition. Safari's Web Inspector lists @container rules in the Styles sidebar and lets you inspect ancestors for container-type. In all three, the fastest test of a hypothesis is to edit the container's width in the Styles pane and watch the rule switch on and off.
Subtler failures: the rule matches, but the wrong way
Not every container bug is a rule that never applies. Some rules apply at the wrong time, which is harder to notice.
The wrong ancestor answered. An unnamed @container rule uses the nearest container of any matching type. When a component is dropped inside another component that also establishes a container, the inner container becomes the one measured, and the thresholds suddenly apply to a much narrower box. Naming the containers each component depends on — container-name: card — makes the relationship explicit and immune to nesting.
Units resolve somewhere unexpected. Container conditions written in em resolve against the container's computed font size, which may differ from the styled element's. Container query units such as cqi inside the rule's declarations resolve against the nearest container for that element, which is not always the container the condition queried. When sizes look off by a consistent ratio, check which container each unit is measuring.
The container changes size because of its own children. An inline-size container ignores its children for its inline size, but a size container with a percentage height, or one inside a grid track sized by content, can change size when the query's styles change what is inside the track. The result is flicker at the threshold as the layout alternates. DevTools shows this as a rule that toggles on every frame; the fix is to give the container a size that does not depend on the queried content.
Styles transition across the threshold. If a transition is declared on a property that the query changes, crossing the threshold animates — which may be the intention, or may look like lag. Temporarily disabling transitions in DevTools distinguishes a slow query from an animation.
Variation: a debugging stylesheet
For a component library, a small opt-in debugging stylesheet makes containers visible without opening DevTools, which helps designers and reviewers see what each component is responding to.
/* Include only in development, or behind a query parameter. */
[data-debug-containers] :where([style*="container"], .cq, [class*="-slot"]) {
outline: 1px dashed #f59e0b;
outline-offset: -1px;
}
/* Label each band the component is in by setting a token per band... */
@container (width < 20rem) { .cq-label::after { content: "compact"; } }
@container (20rem <= width < 40rem) { .cq-label::after { content: "regular"; } }
@container (width >= 40rem) { .cq-label::after { content: "wide"; } }
/* ...and printing it in a corner of the component. */
[data-debug-containers] .cq-label::after {
position: absolute;
inset: 0 0 auto auto;
padding: 0 0.3rem;
font: 10px/1.4 ui-monospace, monospace;
background: #fef3c7;
color: #78350f;
}
The demo shows the idea on a single card: resize the frame and the corner tag updates as the container crosses each band boundary.
Printing the active band in each component turns a silent mechanism into a visible one, which is invaluable when tuning thresholds. The thresholds themselves are best written with the range syntax covered in Container Query Range Syntax and Logic, so bands never overlap. For the collapsed-container problem in depth, see container-type: size vs inline-size. The same DevTools discipline applies to motion: Profiling Animations in DevTools covers the animation side of the panels.
Browser support
Container queries are supported in Chrome and Edge 105+, Firefox 110+ and Safari 16+. DevTools support for inspecting them is present in current versions of all three browsers: Chromium's Elements panel shows container badges and the resolved container for each @container rule, Firefox's inspector shows container query rules and container types, and Safari's Web Inspector lists @container rules in its Styles sidebar. Exact panel names and affordances change between releases, but the resolved-container information is available in all of them.
FAQ
Why does my @container rule never apply?
The most common causes are no ancestor with container-type set, a container name that does not match, a condition on height against an inline-size container, or a container that has collapsed to zero width. DevTools shows which container a rule resolved against, which usually identifies the cause within seconds.
How do I see which element a container query is measuring?
In Chromium DevTools, the Styles pane shows each @container rule with the container it resolved to; hovering it highlights the container on the page, and clicking it selects the container in the Elements tree. Firefox and Safari show the container query condition and let you inspect ancestors to find the container.
Why is my container zero pixels wide?
An element with container-type: inline-size does not use its content to determine its inline size. If it sits in a shrink-to-fit context, such as a flex item without a basis or an absolutely positioned element without a width, it collapses to zero. Give it a width or let it stretch.
Can I test container queries without resizing the browser?
Yes. Change the container's width directly in the Styles pane, or add resize: horizontal with overflow: auto to the container temporarily and drag its corner. Container queries respond to the container, so the viewport does not need to change.
Related
- Container Query Syntax Basics — the parent guide.
- Nesting and Naming Container Queries — how names change which container is found.
- How to Use Container Queries in Production — structuring containers to avoid these bugs.
- Suppressing Motion in Small Containers — container queries that gate animation.
Related articles
More pages in the same section.