🎨 The Container Query That Was Watching an Element That Wasn’t a Container
An @container rule only ever evaluates against the nearest ancestor that has actually been established as a query container via the container-type property – simply nesting an element inside any ancestor and writing an @container rule does nothing at all if that ancestor never opted in. There’s no error, no warning in the console: the rule is valid CSS, it just never has a container to evaluate against, so it silently never applies.
🔎 The Problem
.card-wrapper {
/* Looks like a perfectly reasonable container for the card inside it -
but nothing here actually establishes a query container. */
display: flex;
padding: 1rem;
}
.card {
background: white;
}
@container (min-width: 400px) {
.card {
/* This rule is completely valid, and completely inert - there is
no containment context anywhere above .card for it to query
against, so this block simply never matches, at any width. */
grid-template-columns: 1fr 1fr;
}
}
âś… Fix: Explicitly Opt an Ancestor Into Being a Container
- Adding container-type: inline-size (or size, if height queries are also needed) to the intended ancestor – here, .card-wrapper – along with a container-name if more than one container type is in play, is the one required step that makes the @container rule actually start evaluating.
- DevTools in current versions of Chrome and Firefox both show container query context directly in the layout inspector, including which ancestor (if any) is currently acting as the container for a given element – checking this is the fastest way to confirm the containment chain is actually wired up correctly, rather than guessing from the CSS alone.
- A quick baseline test (an obviously wrong background color applied unconditionally to .card-wrapper, confirmed visible, followed by an equally obvious style applied only inside the @container block) isolates whether the problem is the containment setup or something else in the query condition itself.
⚠️ Why This Is an Easy Step to Skip
- Media queries never required this kind of explicit opt-in from any ancestor, so a developer used to writing @media rules can very reasonably write an @container rule the same way and expect it to just work off proximity alone – container queries are deliberately more explicit than that, precisely so a container’s size doesn’t get implicitly redefined by something further up the tree without an explicit signal.
- This is especially easy to miss in a component-based codebase where the ‘card’ component and its ‘wrapper’ are defined in genuinely different files by different people – the container-type declaration is a one-line addition that’s simple to forget specifically because nothing about the @container rule itself fails to compile or lint without it.
A container query needs an actual container – and CSS is happy to let a perfectly reasonable-looking ancestor sit there doing nothing of the sort, forever, without saying a word about it.
