Skip to content

Build1 publisher3 min readPublished

Container queries pay off component by component, not as a breakpoint purge

A developer refactored a live client site and only added containers where a media query already did the same job. The adoption rule matters more than the feature.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying Container queries pay off component by component, not as a breakpoint purge
Generated illustration

What happened

  • Richard Lemon, writing on dev.to, refactored a real client project - a mid-sized marketing site with a component library, a CMS and legacy CSS - to use container queries.
  • The stated goal was to use container queries wherever component-level decisions made more sense than viewport-level ones, and to keep media queries where they still pull their weight, with no heroic rewrites.
  • The project's original setup used global breakpoint custom properties --bp-xs: 480px, --bp-sm: 640px, --bp-md: 768px, --bp-lg: 1024px and --bp-xl: 1280px, with media queries at min-width 768px and 1024px.
  • Most components were effectively "if viewport is at least md, do layout X, otherwise stack Y".
  • The problem surfaced when the same component lived in different layouts: a hero section inside a full-width page, the same hero in a sidebar-heavy layout, and the same hero inside a CMS block inside a card.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

Richard Lemon has published an account of converting a live client project, a mid-sized marketing site with a component library, a CMS and a pile of legacy CSS, to use container queries where component-level decisions made more sense than viewport-level ones [1][2]. The useful part is not that container queries worked; it is the adoption rule, which keeps the migration bounded: a component got a container only where he had previously written a media query for small-card versus large-card layout [13].

The old system was a set of global breakpoint tokens at 480, 640, 768, 1024 and 1280 pixels, with media queries hanging off 768px and 1024px [3]. Most components reduced to a single sentence: if the viewport is at least md, do layout X, otherwise stack [4]. That holds until the same component appears in a full-width page, a sidebar-heavy layout, and a CMS block inside a card [5]. The hero card is the clean example. It switched to a 3fr 2fr grid at a 768px viewport [6], which meant that in a skinny sidebar on a 1440px screen it still went two-column and looked broken [7]. Rewritten, it takes `container-type: inline-size` and goes two-column at `@container hero-card (min-width: 560px)` [8].

The precondition is structural, not stylistic. Container queries need containers, so the HTML came first, governed by an audit rule: a component that responds to its own width gets a container, and where an inner part responds to the component, the parent becomes the container [9][10]. That produced two patterns. Layout shells, grid sections, sidebars and cards became container roots [11]. Reusable design-system blocks such as `.feature-card`, `.stat-block` and `.media-object` got their own [12].

The clearest payoff is in the CMS. Content blocks that editors can drop into full-width sections, narrow sidebars, or cards inside carousels used to force a governance workaround: he limited where editors could place certain components, purely to protect the media queries [14][15]. That restriction went away [15]. With `@container content-block (min-width: 700px)` driving the image-right variant [16], the same block worked in a 900px region and a 420px sidebar [17]. In other words, one piece of markup resolves to two columns 200px above the threshold and stacks 280px below it, without an author choosing between them [20].

There is a cost line in this, and it is the thresholds. The hero's 560px is not one of the project's five breakpoint tokens [22], and 560 sits 208px below the 768px viewport breakpoint it replaced [19]. Component thresholds are new numbers with their own maintenance, which is the argument for adding them one component at a time rather than declaring the breakpoint system obsolete. His stated position is to keep media queries where they still pull their weight [2], though the published text stops mid-sentence in the CMS section before enumerating those cases, despite the headline promising them [21].

Worth watching: how many components actually pass the audit rule in a real design system, since the count is the migration's true size [10][13]; whether removing CMS placement restrictions changes what editors build [15]; and whether component thresholds end up tokenised like the viewport ones, or drift as loose per-component magic numbers [22].

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories