CSS Container Query Units: cqw, cqi, cqmin and the Rest
What cqw, cqh, cqi, cqb, cqmin and cqmax each measure, when to use which, and the containment they require to resolve.
Table of contents
vw measures the viewport. cqw measures the container. That one substitution is what lets a component size its own type and spacing without knowing anything about the page it landed on.
There are six of these units, and the difference between cqw and cqi is the one that decides whether your component survives a language that reads top to bottom.
Key takeaways#
- Container query units resolve against the nearest ancestor with
container-typeset, not the viewport. cqw/cqhare physical (width/height).cqi/cqbare logical (inline/block) and follow writing mode.- Prefer
cqi. It is the one that stays correct in vertical writing modes, and it matches the axiscontainer-type: inline-sizeactually measures. - Using a unit with no container ancestor is not an error — it silently falls back to the small viewport size, which looks like the unit is broken.
cqminandcqmaxcompare the two logical axes, not the physical ones.
The six units#
| Unit | Measures | 1 unit = |
|---|---|---|
cqw | Container width | 1% of container width |
cqh | Container height | 1% of container height |
cqi | Container inline size | 1% of the inline axis |
cqb | Container block size | 1% of the block axis |
cqmin | Smaller of cqi and cqb | 1% of that smaller axis |
cqmax | Larger of cqi and cqb | 1% of that larger axis |
Each is 1% of its dimension, exactly as vw is 1% of viewport width. A card in a 400px container gets 4px from 4cqw.
What is the difference between cqw and cqi?#
cqw measures the container's width. cqi measures its inline size — the axis text flows along. In a default horizontal writing mode they are identical. In writing-mode: vertical-rl, text flows top to bottom, so the inline axis becomes the height and the two units diverge completely.
This is the same distinction as width versus inline-size, or margin-left versus margin-inline-start. The logical unit follows the content; the physical one follows the screen.
.wrapper {
container-type: inline-size;
}
.card__title {
/* Scales with the axis the container actually measures. */
font-size: clamp(1rem, 5cqi, 2rem);
}Reach for cqi by default. Beyond the writing-mode correctness, it lines up with what container-type: inline-size constrains — you are querying the inline axis, so sizing against the inline axis keeps one mental model rather than two.
Why is my cqw value wrong?#
Almost always because there is no container to measure. Container query units resolve against the nearest ancestor with container-type set, and when none exists the specification says to fall back to the small viewport size — so cqw quietly behaves as svw.
Nothing errors. DevTools shows a computed value. It is simply the wrong number, and on a desktop viewport it is usually far too large.
Three things cause it:
- No
container-typeanywhere up the tree. The most common case, and the easiest to miss because a plain@containerquery would also silently never match. - The container is the element itself. An element cannot query itself.
container-typegoes on the wrapper, and the unit is used on a descendant. - Using
cqhunderinline-sizecontainment. Covered above: the block axis is not constrained, so it falls back.
Checking is quick — set an obvious value like width: 50cqi and see whether the element becomes half its container or half the screen.
Fluid type that respects the component#
The pattern container units unlock is type that scales with the component rather than the window. A card in a sidebar and the same card in a wide main column get proportionally sized headings, from one rule:
.card-wrapper {
container: card / inline-size;
}
.card__title {
font-size: clamp(1.125rem, 4cqi, 1.75rem);
}
.card__body {
font-size: clamp(0.875rem, 2.5cqi, 1rem);
padding-inline: 4cqi;
}clamp() matters here rather than being decoration. Raw 4cqi keeps shrinking in a narrow container until the text is unreadable, and keeps growing in a wide one. The clamp sets the floor and ceiling; the container unit handles everything between.
Padding expressed in cqi is the other half of the trick. A card at 280px gets 11px of inset and the same card at 700px gets 28px, so the proportions hold instead of the padding looking mean at one size and wasteful at the other.
cqmin, cqmax, and what they actually compare#
cqmin resolves to 1% of whichever is smaller, the inline size or the block size. cqmax takes the larger. Both compare the logical axes, so in a vertical writing mode the physical meaning swaps with everything else.
They earn their place for square-ish things that must stay square-ish — an avatar, an icon, an aspect-locked media slot — where sizing against a single axis lets the element overflow when the container is tall and narrow:
.avatar {
width: 20cqmin;
height: 20cqmin;
}Both need container-type: size to be meaningful, since cqmin has to know the block axis. Under inline-size containment the block axis falls back to the viewport, and the comparison is between a real number and an unrelated one.
Container units versus viewport units#
They answer different questions and both remain useful.
| Viewport units | Container units | |
|---|---|---|
| Measures | The window | The nearest sized ancestor |
| Right for | Page shells, hero sections, full-bleed layout | Components that must be reusable |
| Breaks when | The component moves into a narrower column | No container-type is declared |
| Fallback | none needed | Small viewport size, silently |
The rule that holds up: viewport units for the page frame, container units for anything that might get reused somewhere you did not anticipate. A component that reads vw is making a claim about the page, and that claim expires the first time someone drops it into a sidebar.
Browser support, as of August 2026#
Container query length units ship in current Chrome, Edge, Firefox and Safari, alongside size container queries themselves. The practical constraint is not support but the silent viewport fallback — a browser that did not understand cqi would ignore the declaration and take your previous value, so a sensible non-container fallback earlier in the cascade degrades cleanly:
.card__title {
font-size: 1.25rem; /* taken if cqi is unsupported */
font-size: clamp(1.125rem, 4cqi, 1.75rem);
}For the containment rules these units depend on, see container-type: inline-size vs size.
Container query units are easy to mistype and hard to spot in a long rule. The CSS Formatter will lay a stylesheet out so the units are visible at a glance.
Tags
- CSS
- Responsive
- Layout
- Design Systems