CSSThe Switcher Layout

The Switcher Layout

The Switcher is another Every Layout pattern: a row of items that automatically becomes a column once the container gets too narrow to fit them comfortably — with no media query deciding where that happens. The trick is a flex-basis calculation that flips sign at exactly the width you choose.

The core recipe

CSS
.switcher {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.switcher > * {
  flex-grow: 1;
  flex-basis: calc((32rem - 100%) * 999);
}

That one calc() line is the whole trick — worth reading carefully.

How the calc() flip works
  • 32rem is the threshold — the container width below which items should stack. Call it the target.

  • When the container is wider than the target, 32rem - 100% is a negative number. Multiplied by 999, it becomes an enormous negative flex-basis — flex clamps a negative basis to 0, so items shrink to their content width and sit in a row.

  • When the container is narrower than the target, 32rem - 100% is a small positive number. Multiplied by 999, it becomes an enormous positive flex-basis — far bigger than any container could satisfy on one line, so each item is forced onto its own row.

  • The multiplier (999) just needs to be big enough that the resulting basis is always either deeply negative or deeply positive — a "digital" switch rather than a graceful one, which is exactly the point.

Note
No @media query appears anywhere in this pattern. The break point is expressed once, as the 32rem constant inside the calculation, and it reacts to the switcher's own container width — not the viewport — so it works correctly nested inside a narrow sidebar too.
Controlling how many columns appear

Left alone, a Switcher with many children just keeps them all on one row once past the threshold — useful for a button group, less useful for a card grid that should wrap into multiple rows of two or three. Cap it by fixing a max child count per row with nth-child.

CSS
/* limit to a max of 3 per row above the threshold */
.switcher > :nth-last-child(n + 4),
.switcher > :nth-last-child(n + 4) ~ * {
  flex-basis: 100%;
}
Tip
This is the "quantity query" idea — styling based on *how many* siblings are present rather than the viewport. :nth-last-child(n + 4) matches only when there are 4 or more items total, letting a 2- or 3-item row stay a simple row while a 4+ item row forces additional wrapping.
Use case — form rows that collapse to a column

HTML
<div class="switcher">
  <label>First name<input /></label>
  <label>Last name<input /></label>
  <label>Email<input type="email" /></label>
</div>

On a wide form the three fields sit in a row; embedded in a narrow modal or a mobile viewport, the same markup and CSS stack them vertically automatically — no separate mobile stylesheet needed.

Use case — a card row that becomes a card stack

CSS
.card-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.card-row > .card {
  flex-grow: 1;
  flex-basis: calc((40rem - 100%) * 999);
}

Drop this exact component into a full-width page (stays a row of cards) or into a narrow sidebar widget (collapses to a stack) — the same rule adapts to whatever container it lands in, which is the entire value proposition of an intrinsic, container-aware layout.

Switcher vs media-query row/column toggling

Switcher (calc trick)

Media query toggle

Breakpoint tied to

The container itself

The viewport, regardless of container

Reusable inside any container width

Yes

Only if you re-tune the breakpoint per context

Extra selectors needed for column cap

One nth-child rule (optional)

None — usually already per-breakpoint

Readability for future maintainers

Requires understanding the calc trick

Immediately obvious

Note
In codebases where container-type: inline-size and container queries (see the Container Queries page) are already a safe baseline, a container query can express the same "switch at this container width" intent more readably than the calc trick — the Switcher pattern remains valuable mainly where you want zero extra wrapping elements or need to support older browsers.