CSS & layout

Container queries observe the component, not the viewport

Container queries observe the component, not the viewport

Drop a card component into a two-column layout. In the wide column it lays out as a row: image left, copy right. Move the same card into a 320px sidebar and it still tries to be a row, because its breakpoint was written against the viewport, not the box it now lives in. That is the pattern Victor Ayomipo, writing in Smashing Magazine on 16 September, is trying to get you to stop shipping.

Where each query lives

Media queries answer the browser. Container queries answer the box.

Ayomipo frames it as "macro" vs "micro" layout. A media query asks the viewport how wide the page is. A container query asks a specific ancestor element how wide it is. Reuse the same breakpoints across both and the component reads the wrong signal.

The State of CSS numbers he cites explain why the mismatch keeps happening: 86% of developers know container queries exist, and 41.4% actually use them. Browser support sits at roughly 94% (caniuse.com), so the gap is not the engines. It's the habit of copying media-query shapes into new syntax.

The two-line wiring

The minimum shown in the source to make a card respond to its own width:

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

@container card (min-width: 450px) {
  .card {
    display: flex;
    flex-direction: row;
  }
}

container-type: inline-size gives the wrapper a size a descendant can query. container-name labels it. Then @container card (...) reads that wrapper's inline size, not the viewport. Drop the card in a 300px rail: the row layout stays off. Drop it in a 600px column: it flips. Same component, two contexts.

One rule to internalise, per the article: you cannot query the element you are styling. The component and its container have to be different nodes, or the layout goes into a loop. That is the reason for the wrapper.

Container units, same idea

Container units are the other half. Ayomipo's typography example:

.card-title {
  font-size: clamp(1rem, .5rem + 3cqi, 2rem);
}

cqi is 1% of the container's inline size. Wired to a container-type: inline-size ancestor, clamp() gives the title a floor, a ceiling, and a smooth ramp between them driven by the box rather than the viewport. The card grows and shrinks with its column. No media-query stack, no per-breakpoint font sizes.

The rough edges

The article walks through a flex-wrap detection pattern for a card grid: flex items sized flex: 1 1 390px are each given container-type: inline-size, then an @container (min-width: 600px) rule flips a card from column to row once it stops sharing its row with siblings. The card notices when it is alone. The viewport is not involved.

Ayomipo also flags the sharp corners. Querying block size can collapse a layout when the container has no explicit height. Custom-property values do not work inside a container-query condition, so a shared --breakpoint variable is out. And the wrapper element is real DOM; a component still cannot query itself.

What to try next

Pick one component on your current project that reads viewport width — a card, a media object, a summary tile. Wrap it, set container-type: inline-size on the wrapper, and rewrite its breakpoints as @container rules with cqi for the type ramp. Drop it in three contexts on the same page. If it renders the same layout in a 300px rail and a 900px column, the breakpoints are still viewport-shaped. Kevin Powell, quoted from a SmashingConf Amsterdam 2026 talk, called container-query adoption "terrible" for exactly that reason.

Source: Smashing Magazine (smashingmagazine.com)

Related
CSS & layout

Grid Lanes masonry settles on Grid syntax, and flow-tolerance is now fit-tolerance

A Piccalilli walkthrough by Saleh Mubashar traces native CSS masonry from its 2017 CSSWG issue to display: grid-lanes, and notes that the lane-picking property is now called fit-tolerance. Per the article, Grid Lanes works in Safari 26.4 and later, and support in other browsers is still evolving.

October 24, 2026
CSS & layout

The Interop 2027 CSS shortlist reads like a list of hacks you get to delete

Josh W. Comeau has published his ten CSS picks for Interop 2027, from @function and corner-shape to gap decorations and scroll-state queries. The support tables in his post, current as of October 2026, mark nine of them as supported in Chrome 155 and Edge 154 but not in Firefox 157 or Safari 27, and he argues several already work as progressive enhancements.

October 21, 2026
CSS & layout

Overlap detection lands in CSS with anchors and a shared timeline

Ahmad Shadeed shows how to notice when a decoration collides with a section using only CSS: anchor positioning measures the gap, a scroll-driven timeline carries the reaction, and timeline-scope shares it between siblings.

September 25, 2026