TLDR: If your CSS variables use
cqiunits, never apply them tohtml— even inside a sharedhtml, body {}rule. Setfont-sizeonbodyonly. One misplaced selector can push your root font-size 2–3× too large and silently break everyrem-based clamp in your stylesheet.
The Setup
I was building a presentation site for a marketing client AI workshop — full-screen 16:9 stages, snapping panels, a fluid type system built on a single --body CSS variable using clamp() with cqi (container query inline units) to scale text to the stage.
Looked clean in dev.
Then I opened it on a big monitor.
The Wall
Every slide overflowed.
Not a little — 100–200px past the bottom edge of the 16:9 frame. Cards too tall. Body text enormous. H2 wrapping to two lines when it had no business doing so.
I assumed it was the card padding. Trimmed it. Still broken.
Tightened the type maxes. Rewrote the gallery layout. Cut a panel. Reduced clamp ceilings. Twelve commits. Still broken "in multiple places" — but the places kept shifting.
That's when I knew it wasn't a content problem.
What I Should Have Done First
I was debugging symptoms. The root was somewhere else entirely.
So I finally measured.
arc-cdp eval 'JSON.stringify({
rootFs: getComputedStyle(document.documentElement).fontSize,
bodyFs: getComputedStyle(document.body).fontSize
})'
(arc-cdp is my Arc browser automation tool — lets me eval JavaScript in the live page from the terminal.)
The result: rootFs: "36px".
Thirty-six. Browser default is 16px.
The Actual Bug
Here's the CSS:
:root {
--body: clamp(0.95rem, 1.7cqi, 2.25rem);
}
html, body {
font-size: var(--body); /* ← the bug */
}
The --body variable uses 1.7cqi — 1.7% of the container's inline width.
html has no container. When you use cqi on a containerless element, it falls back to the viewport.
On a 2540px-wide viewport: 1.7% × 2540 = 43px. The clamp (15.2px, 43px, 36px) returns 36px. Root html font-size = 36px.
Now every rem downstream resolves against 36px instead of 16px. So this innocent rule:
.card p { font-size: clamp(0.85rem, 1.3cqi, 1.7rem); }
…suddenly had a 30.6px floor. On a normal viewport the cqi midrange was only ~21px — so the rem floor won every time. Responsive sizing: completely broken, everywhere, all at once.
One selector. Everything downstream: wrong.
The Fix
html {
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
/* everything EXCEPT font-size */
}
body {
font-size: var(--body); /* body only */
}
That's it. One line moved from html, body to body alone.
Root html stays at the browser default 16px. Every rem-based clamp inside the stage elements now computes correctly — and the cqi midrange wins as designed.
Single commit. Every overflow: gone.
Why This Matters
Any container-relative unit (cqi, cqb, cqmin, cqmax) applied to a containerless element falls back to the viewport. And html is always containerless.
If you've ever set font-size on html using a variable that contains a container unit — directly or through a shared html, body {} selector — your rem scale is probably wrong on large screens and you don't know it yet.
The debugging move I wish I'd made on commit one:
getComputedStyle(document.documentElement).fontSize
If that's not 16px (or whatever you intended), STOP. That's the bug. Don't trim card padding. Don't touch type scales. Measure first.
I lost an afternoon chasing symptoms. You don't have to.
P.S. This is now the first thing I check when CSS overflows don't respond to the obvious fixes. Measure the root before you touch anything else.