Container Query Units: Using cqw, cqh, cqi and cqb in Practice
AI generated
{ }
@
CSS · Container Queries · Responsive Design
Container Query Units
Using cqw, cqh, cqi and cqb in practice

Container query units scale font sizes and spacing relative to the width or height of the surrounding container, not relative to the browser window. That means a card component automatically behaves differently in a narrow sidebar than the same card in a wide main area, without extra classes or JavaScript.

15 min read cqw · cqh · cqi · cqb Container Queries · CSS 2023+

1. What container query units are and why they complement viewport units

The units cqw, cqh, cqi and cqb behave syntactically like vw and vh, but refer to the size of the nearest query container instead of the browser window. One 1cqw equals one percent of that container's width, not the page's width. That sounds like a small shift in the reference size, but it fundamentally changes how a component scales across different layout contexts.

Before container query units, a component was either tied to the viewport, which made text tiny inside a narrow sidebar, or tied to fixed pixel values that never really fit any context. With cqi and its related units, a component scales relative to the space it actually has available, whether it ends up in a sidebar, a modal, or a full-width grid.

2. Prerequisite: setting container-type on the parent element

Container query units only work inside an element that has been declared a query container with container-type. Without that declaration, the units fall back to the next ancestor container, or effectively resolve to zero if none exists. The most common value is container-type: inline-size, because it only tracks the inline direction, usually the width, and avoids the more expensive block-size tracking.

An optional container-name lets you target a specific one of several nested containers, in case a component needs to reference an outer container rather than the nearest one. For most practical cases, however, the implicit reference to the nearest container is enough, with no explicit name required in the unit declaration itself.


.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  /* Font size scales with container width, not the viewport */
  font-size: clamp(0.95rem, 0.85rem + 1.5cqi, 1.25rem);
  padding: clamp(0.75rem, 2cqw, 1.5rem);
}

3. Scaling font sizes with cqi: the card example in detail

cqi stands for container query inline size and refers to the container's inline axis, which in a classic horizontal writing mode means its width. Combined with clamp(), it produces a font size that grows smoothly between a minimum and a maximum as the container gets wider, but never becomes unreadably small or awkwardly large.

The advantage over pure viewport units shows up immediately in a dashboard layout: a stat card sitting in a three-column overview automatically gets smaller text than the same card rendered at full width in a detail view, even though the viewport is identical in both cases. The component reacts to the space it actually has, not to the window size.

4. Scaling spacing and inner padding consistently with cqw and cqi

It is not only font sizes that benefit from container query units; padding, gap and margin can also be defined relative to the container width. That keeps the ratio between text and whitespace proportionally stable across container widths, instead of looking either too tight or too generous at a fixed pixel value.

A proven pattern is defining a card's inner padding as clamp(1rem, 3cqw, 2rem): in a very narrow sidebar, the padding stays at one rem, then grows proportionally with the container width, and caps at two rem once the container is wide enough. That keeps the layout balanced in every context without needing a separate media query for every breakpoint step.


.stat-card {
  container-type: inline-size;
}

.stat-card__inner {
  padding: clamp(1rem, 3cqw, 2rem);
  gap: clamp(0.5rem, 1.5cqw, 1rem);
  display: flex;
  flex-direction: column;
}

.stat-card__value {
  font-size: clamp(1.5rem, 1rem + 4cqi, 2.5rem);
  font-weight: 700;
}

5. cqb and cqh: the block axis and when it actually matters

cqb (container query block size) refers to the container's block axis, which in horizontal writing mode means its height. cqh is the direct counterpart to vh and always refers to height, regardless of writing mode. Both require container-type to be set to size instead of only inline-size, so the browser actually tracks the container's block dimension.

In practice, these two units come up less often than cqw and cqi, because heights in web layouts are usually driven by content rather than the other way around. They become useful for fixed-dimension containers, for example a video player with a defined height whose controls should scale proportionally to the player height, or for cards in a CSS grid with a fixed row height.

6. A practical recipe: a component that adapts itself to any context

The real promise of container query units shows up once the same component is copied unchanged into multiple layout contexts. A product card that appears both in a narrow sidebar recommendation and in a wide category page grid no longer needs context-specific modifier classes, because it derives its typography and spacing directly from the width it is given.

The setup stays remarkably simple: the outer wrapper gets container-type: inline-size, and the inner elements exclusively use relative units like cqi and cqw combined with clamp() for sensible upper and lower bounds. That is enough to build an entire component system where every single component knows on its own how to behave in tight or generous space.