frontend / css / 02_container_queries_and_subgrid.md

Container Queries and Subgrid

3 min read source

Container Queries and Subgrid

TL;DR

Two modern layout features that fix long-standing gaps. Container queries (@container) style an element by the size of its container rather than the viewport — true component-level responsiveness, so the same card adapts whether it’s in a wide main area or a narrow sidebar. Subgrid lets a nested grid align to its parent’s tracks, so content in sibling cards lines up across cards. Both are baseline-available in current browsers.

Interview Q&A

Q: What problem do container queries solve that media queries can’t?

A: Media queries respond to the viewport, but a reusable component doesn’t know how wide it will be rendered — it depends on where it’s placed. Container queries respond to an ancestor container’s size, so a component is responsive to its own context:

.card-wrap { container-type: inline-size; }   /* establish a query container */

@container (min-width: 400px) {
  .card { grid-template-columns: 120px 1fr; }  /* side-by-side when the container is wide */
}

Drop that card in a 320px sidebar → stacked; in an 800px main → side-by-side. No viewport breakpoints, no knowing the layout in advance.

Q: How do you set up a container, and what’s container-type?

A:

  • container-type: inline-size — query the width only (most common; height stays content-driven).
  • container-type: size — query width and height (requires the container to have a definite size, or it collapses).
  • container-type: normal — not a size container (still usable for style/container-name).
  • container-name: card + @container card (…) — name containers to target a specific ancestor.

Shorthand: container: card / inline-size;.

Q: What are container query units?

A: Length units relative to the query container: cqw/cqh (1% of container width/height), cqi/cqb (inline/block size), cqmin/cqmax. Useful for fluid type/spacing scaled to the component:

.card h2 { font-size: clamp(1rem, 5cqi, 2rem); }   /* scales with the card, not the viewport */

Q: What is subgrid and what does it fix?

A: A nested grid normally has its own independent tracks. grid-template-columns: subgrid (or -rows) makes the child grid adopt the parent’s track lines, so descendants align across separate grid items:

.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.card  { display: grid; grid-row: span 3; grid-template-rows: subgrid; }
/* each card's title / body / footer align on shared rows across all cards */

Without subgrid, each card’s internal rows size independently and titles/footers don’t line up when content length differs. Subgrid is the clean fix for “make these card sections align.”

Q: Container queries vs media queries — do you replace one with the other?

A: They’re complementary. Media queries still suit page-level layout (overall columns, navigation mode) and non-size conditions (prefers-color-scheme, prefers-reduced-motion, print). Container queries suit component-level adaptation. Modern systems use media queries for the shell and container queries for reusable components.

Gotchas / edge cases

  • You can’t query the element itself@container queries the nearest ancestor container, so you need a wrapper element to be the container (a component can’t be its own size container for its root). Plan one wrapper per queryable component.
  • container-type: size needs a definite height or the container has zero block size and collapses; inline-size is the safe default.
  • container-type establishes containment (layout/style/inline-size) — it creates a new containing context, which can affect things like position: fixed descendants and % heights. Mostly fine with inline-size.
  • Subgrid only inherits tracks in the axis you setsubgrid on rows doesn’t affect columns; set both if needed. The gap can be inherited or overridden.
  • Naming collisions — unnamed @container matches the nearest container of any name; name containers when nesting to avoid querying the wrong ancestor.

What a senior is expected to say

  • “Container queries make components responsive to their container, not the viewport — the same card adapts to sidebar vs main without knowing the layout. I set container-type: inline-size on a wrapper, since an element can’t query itself.”
  • “Container query units (cqi) scale type/space to the component.”
  • “Subgrid lets nested grids adopt the parent’s tracks so sibling cards’ sections align — the clean fix for cross-card alignment.”
  • “They complement media queries: MQ for the page shell and non-size conditions, CQ for reusable components.”

Cross-references

Further reading