skip to content

A CSS @container (min-width: 400px) block never applies even though the element is clearly wider than 400px on screen. What are the likely causes?

level: seniorimportance: should knowfreq 42%

answer

  1. it fails silently, so work a checklist
  2. is anything actually a container
  3. an element cannot query itself
  4. nearest ancestor container wins
  5. axis must match the container-type

basics

~20 s

Usually no ancestor declared container-type, or the element being styled is itself the container — an element cannot match its own query. Other causes: a name that matches no ancestor, a nearer container shadowing the intended one, or a height condition against an inline-size container.

solid answer

~50 s

I work through a short list. First, is there an ancestor with `container-type: inline-size` or `size`? Without it there is no query container and the block is dead. Second, is the element I am styling the container itself? An element never matches a query against its own container, so `container-type` has to sit on a wrapper. Third, if the query is named, does any ancestor actually carry that `container-name`, spelled identically? A name with no matching ancestor silently never matches. Fourth, is a *nearer* container shadowing the one I meant — an unnamed query always resolves to the closest ancestor container, which in nested layouts is often not the one I had in mind. Fifth, am I querying `min-height` against an `inline-size` container, where the block axis is not queryable? And last, the container's own box may genuinely be narrow even though the content looks wide — a shrink-wrapped wrapper, or overflowing content.

go deeper

for a junior

Know the two first checks: some ancestor must declare container-type, and the rules inside @container apply to that container's descendants rather than to the container itself.

for a middle

Explain why self-querying is forbidden — the rule would change the width the condition just measured — and how an unnamed query picks the nearest ancestor container.

for a senior

Work a diagnostic order out loud, including the subtle causes: a nearer container shadowing the intended one, an axis the container-type does not expose, and a container that silently collapsed under containment.

for a principal

Own the prevention: a convention for where containers are declared and named so nesting stays predictable, plus review or lint expectations that stop self-queries and stray container-types reaching the codebase.

## Why this fails silently A container query that cannot resolve does not error, does not warn, and does not fall back — the block simply never matches. That makes it a debugging exercise rather than a syntax fix, and the causes are a short, memorable list. ## 1. No ancestor is a query container `container-type` defaults to `normal`, meaning "not a size query container". If nothing above the element opts in, there is nothing to query. ```css /* nothing here is a container */ @container (min-width: 400px) { .card { … } } /* never matches */ ``` Related near-miss: `contain: layout` or `contain: content` on an ancestor does **not** make it a query container. Only `container-type` (or the `container` shorthand) does. Assigning `container-name` alone does not either — a name without a type is just a label on a non-container. ## 2. The element is trying to query itself This is the most common cause in real code: ```css .card { container-type: inline-size; } @container (min-width: 400px) { .card { display: grid; } } ``` An element is never matched by a query against the container it *is*. The specification excludes it deliberately: if the rule could change the element's own width, the query condition would depend on its own result. The fix is structural — move `container-type` to a wrapper: ```css .card-slot { container-type: inline-size; } @container (min-width: 400px) { .card { display: grid; } } ``` If the component owns its own markup, this means adding a wrapper element, which is exactly why component libraries ship a slot element around each card. ## 3. The name matches nothing ```css .card-slot { container: card / inline-size; } @container cards (min-width: 400px) { … } /* typo: cards vs card */ ``` A named query that finds no ancestor with that `container-name` never matches. Container names are case-sensitive idents, and there is no diagnostic. This also happens after a refactor renames the wrapper but not the queries. ## 4. A nearer container is shadowing the intended one An unnamed `@container` resolves against the **nearest** ancestor query container. In a nested layout, the nearest is often not the one you were reasoning about: ```css .region { container-type: inline-size; } /* the wide one you meant */ .card-slot { container-type: inline-size; } /* the narrow one that wins */ ``` The card's unnamed query measures `.card-slot`, which may be 280px even though `.region` is 900px. The fix is to name the containers and query the intended one explicitly, or to remove the intermediate container if it was not needed. ## 5. Querying an axis the container does not expose `container-type: inline-size` makes only the inline axis queryable. A `min-height` or `height` condition against it cannot be evaluated and therefore never matches: ```css .panel { container-type: inline-size; } @container (min-height: 300px) { … } /* never matches */ ``` Querying block size requires `container-type: size`, which contains both axes — and that is only safe when the container has a definite height. Adding it to an auto-height wrapper collapses the wrapper to zero height, at which point the height query still fails, now for a different reason. ## 6. The container really is narrow The element on screen looking wide is not proof that the *container* is wide. Two cases recur: - The container shrink-wrapped. Under inline-size containment the container's intrinsic inline size is computed as if it had no content, so a float, inline-block, `fit-content` box, or content-sized grid or flex item collapses. The children still paint at their own width and overflow, so the page looks fine while the container measures nearly zero. - The content overflows a genuinely narrow container. Same visual, same wrong conclusion. ```css .card-slot { display: inline-block; /* was sized by its content */ container-type: inline-size; /* now measures ~0 */ } ``` Give the container a definite inline size, or move `container-type` onto a block-level ancestor that is parent-sized. ## A working diagnostic order 1. Inspect the intended container and confirm a `container-type` in its computed styles. 2. Confirm the styled element is a **descendant** of it, not the container itself. 3. If the query is named, confirm the ident matches exactly. 4. Walk up from the styled element and find the *first* container — that is the one an unnamed query uses. 5. Check the queried axis against the declared `container-type`. 6. Measure the container's own box, not the content inside it. Browser devtools mark query containers in the elements panel and show which container a `@container` rule resolved against, which collapses most of this list to a single look.

  • An unnamed container query is matching, but against the wrong ancestor. How do you fix it without restructuring the markup?
    Give the containers explicit names with `container-name` and reference the intended one in the query — `@container layout-region (min-width: 60rem)`. Named queries skip past nearer containers whose names do not match, so the inner container stops shadowing the outer one and the markup stays as it is.
  • Why does adding container-type to a shrink-wrapped element make its container query stop matching?
    Inline-size containment computes the element's intrinsic inline size as if it had no content, so a float, inline-block or `fit-content` box collapses to padding and border. Its children still paint and overflow, so the layout looks unchanged while the container itself measures near zero and no width condition matches.
  • Does contain: content or contain: layout on an ancestor make container queries work?
    No. Those apply containment but do not register the element as a query container — only `container-type` (or the `container` shorthand) does that. It is a common assumption because container queries are built on containment, but the query machinery keys off the container-type property specifically.

saying these in an interview costs you the question

  • Puts container-type on the element it then styles
  • Assumes container-name alone makes an element queryable
  • Thinks contain: layout is enough to enable @container
  • Queries min-height against an inline-size container
  • Concludes the container is wide because its content looks wide

context