10LOC
Web Platformintermediate

Container queries for component-level responsive design

Published December 8, 2026

.card-wrapper {
  container: card / inline-size;
}

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

@container card (min-width: 400px) {
  .card {
    grid-template-columns: auto 1fr;
    align-items: center;
  }
}

What

container: card / inline-size turns .card-wrapper into a named query container. The @container card (min-width: 400px) rule then styles .card based on that container's width, not the browser viewport's.

Why it matters

A media query only ever answers "how wide is the viewport?" That's the wrong question for a reusable component: the same card can sit in a 1200px-wide main column or a 280px sidebar on the exact same page at the exact same viewport width, and a media query has no way to tell those two placements apart. Before container queries, "respond to my container's width" meant either ResizeObserver and JS-toggled classes, or giving up and shipping one layout that's a compromise for every context the component ends up in.

Container queries move that responsiveness into CSS, scoped to wherever the component actually lives, with no JavaScript and no layout-thrashing resize listener.

How it works

  • container: card / inline-size is shorthand for container-name: card plus container-type: inline-size. inline-size containment means the container is queried by its inline-axis size (width, in horizontal writing modes) — the common case, and cheaper for the browser than full size containment on both axes.
  • Naming the container card lets @container card (...) target this specific container even if it's nested inside another, unnamed or differently-named container — without a name, an @container query matches the nearest any container, which gets ambiguous once containers nest.
  • @container card (min-width: 400px) { .card { ... } } applies its declarations only when .card-wrapper's content-box width is at least 400px — switching the card from a stacked, single-column layout to a two-column one with room to spare.

Gotchas

  • An element can't query itself. container-type has to be set on an ancestor (.card-wrapper here), and the @container rule styles descendants of that ancestor — never the container element itself for size queries.
  • Setting container-type: size (rather than inline-size) applies layout containment on both axes, which affects how the container's own height is computed by its parent — usually not what you want unless you're deliberately giving the container a fixed size some other way.
  • This CSS block is 13 lines by the repo's line-count rule, past the 6-11 target, hence lineWaiver: true. Cutting the container declaration or the base .card layout would leave a query with nothing meaningful to override.

Related

  • ResizeObserver — the JS equivalent; still the right tool when the response to a size change is more than styling (e.g. re-measuring text, choosing what content to render).
  • Media queries — still correct for page-level layout decisions (nav collapse, overall grid) that really are about the viewport, not a specific component.