ESC

Type to search the knowledge base.

Container Queries

Style components from their container size with @container — name containment, units like cqi, and when media queries still win.

intermediate3 min read
  • css
  • container-queries
  • responsive

Media queries answer “how wide is the viewport?” Card components often live in a narrow sidebar or a wide main column on the same page. Container queries style a component from its parent container’s size so the same .card class can go dense or expanded without viewport hacks.

Docs: MDN container queries, @container, web.dev CQ.

Establish a containment context

.sidebar,
.main {
  container-type: inline-size; /* query width (inline axis) */
  container-name: panel;
}

container-type:

Value What you can query
inline-size Inline size (usually width) — most common
size Both axes (requires definite block size too)
normal Default; not a size query container

Shorthand: container: panel / inline-size;

Query the container

.card {
  display: grid;
  gap: 0.75rem;
}

.card__media {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

@container panel (min-width: 28rem) {
  .card {
    grid-template-columns: 10rem 1fr;
    align-items: center;
  }
}
<aside class="sidebar">
  <article class="card">…</article>
</aside>
<main class="main">
  <article class="card">…</article>
</main>

Same markup, different layout per slot width.

Container query units

Inside a container context, units resolve against the container:

Unit Meaning
cqi 1% of container inline size
cqb 1% of container block size
cqmin / cqmax min/max of those
cqw / cqh width/height percentages (physical)
.card__title {
  font-size: clamp(1rem, 2.5cqi + 0.75rem, 1.5rem);
}

Fluid type tied to the component, not the viewport.

Named vs nearest

@container (min-width: 400px) { /* nearest ancestor container */ }
@container panel (min-width: 400px) { /* only named panel */ }

Name containers when nested wrappers each establish containment and you need a specific ancestor.

Containment side effects

container-type: inline-size applies size containment on the inline axis — the browser optimizes by treating the container’s size as independent in ways that can affect percentage heights and overflowing descendants. If something “won’t grow with content” oddly, inspect containment.

You need an actual container ancestor. Querying without container-type on any parent does nothing useful.

CQ vs media queries

Use Tool
Page chrome, nav collapse, root typography @media
Reusable card/list/widget density @container
User preferences (motion, contrast, scheme) @media feature queries
Device capability @media / @supports

They compose: viewport for shell, container for components.

Interview out-loud

“Container queries let components respond to their parent’s size. I set container-type: inline-size (and usually a name) on the layout slot, then @container name (min-width: …) for component variants. cqi units size things relative to that container. Media queries still handle viewport-level layout and preference features.”

Footguns

  1. Putting container-type on the same element you style with @container — queries look at an ancestor container.
  2. Using size without a definite height.
  3. Expecting CQ in ancient browsers without fallback layout.
  4. Over-nesting named containers until nobody knows which query fires.
  5. Replacing every media query blindly — page-level breakpoints still belong at the shell.

Further reading

Related guides