Container query units resolve against an ancestor container, never the element's own
Fact
cqw, cqh, cqi and cqb measure the nearest ancestor container. An element that declares container-type does not become its own query container, because the answer would feed back into the size it was measured from.
So a container unit written in a rule that targets the container itself measures something else entirely — the next container up, or, if there is none, the small viewport:
.stage {
container-type: size; /* 1008px wide here */
perspective: 120cqw; /* resolved against the 1366px viewport */
}
The same declaration one element down is correct, which is what makes it hard to see: .stage > .camera { perspective: 120cqw } measures the stage.
Why it matters
Nothing errors and nothing is obviously broken. The property takes a plausible value that is wrong by whatever ratio the two boxes happen to have — 36% in the case above — so the symptom is a design that looks subtly off (a flat-looking perspective, padding that breathes wrong at one breakpoint) rather than a unit bug. It is invisible whenever the element and the outer container are close in size, which is most of the time during development.
Custom properties make it worse, because a cq length in a custom property is resolved where it is used, not where it is declared. One --room: 140cqw on the container can mean one length in the container's own rules and a different one in every descendant that reads it — half the geometry right, half wrong.
How to apply
- Never write
cq*in a declaration on the element carryingcontainer-type. Put those properties on a child wrapper that exists for the purpose. - Read a computed value back when a container unit drives geometry:
getComputedStyle(el).perspectiveagainst the container's owngetBoundingClientRect().widthsays immediately which box won. - For "a fraction of this element's own size", prefer
%where the property accepts it;perspective,translateZandbox-shadowoffsets do not, so those are the ones that need the wrapper. - Sizing a descendant against the container is the normal, correct use — see [[overlay-units-follow-the-stage]].