TLDR: CSS grid items default to min-width: auto. If one column holds a <pre> block with long lines, the whole layout blows past the viewport. Fix: minmax(0, 1fr) on the track AND min-width: 0 on the item. Measure it first with Arc CDP (my browser-automation tool) so you know you're chasing the right offender.

The Setup

I was building a client onboarding page on Vercel — a dual-audience page (human reader + AI agent, same HTML) to onboard my client into their new Claude Code setup.

Two-pane layout. Left column: intro text. Right column: install commands and <pre><code> blocks with long shell commands.

Shipped it. Went to click around.

Side-scroll. The page could side-scroll.

Not cool.

My First Instinct (Wrong)

My first move was to go after the <pre> blocks.

Slapped on overflow-x: auto. Tried max-width: 100%. Poked at white-space settings.

Nothing worked — or rather, nothing worked fully. The page still had horizontal overflow.

That's because I was fixing the child. The bug lived upstream.

How I Actually Found It

I ran a quick Arc CDP (browser DevTools automation) probe before touching any more CSS:

const dw = document.documentElement.scrollWidth;
const vw = document.documentElement.clientWidth;

The numbers were embarrassing.

Right column: 1674px on a 2036px viewport. Page docWidth: 2455px. That's 419px of overflow.

The offenders list pointed straight at the grid-item div — not the <pre> inside it, but the column itself. The column had inflated to fit its content instead of respecting the 1fr track it was supposed to fill.

The Root Cause

CSS grid items default to min-width: auto.

That means the browser sizes the track to the intrinsic minimum of its content — and for a <pre> block with a long, unbreakable install command, that minimum is the full character width of the longest line.

So the 1fr track I thought I had? Gone. The column just… grew to match the text.

Fix the grid track, not the child.

The Fix (All Three Together)

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.split > * {
  min-width: 0;
}

pre {
  overflow-x: auto;
  max-width: 100%;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

minmax(0, 1fr) on the track AND min-width: 0 on the items — both are necessary.

Setting one alone can leave the other path open depending on the browser. Belt-and-suspenders: overflow-x: hidden on html and body as a last-resort backstop.

Why This Matters

I've hit this exact pattern now on grid layouts, flex layouts, presentation stages — anytime a container holds code samples, file paths, or long strings.

The lesson I keep re-learning: measure before iterating. One CDP snippet and I had the real offender in 30 seconds. Without it I'd have spent an hour blaming the <pre>.

Set min-width: 0 from day one on any grid or flex column that will hold code. Don't wait for the report.