Step 1 — What the Browser Is Allowed to Skip
Goal
Establish that rendering cost is a property of your CSS instructions, not your DOM size — and distinguish two tools that are constantly confused.
Predict first
3,000 cards × 12 rows = 261,011 DOM nodes, in a 1200×800 viewport. Three variants: no
containment, content-visibility: auto, contain: strict.
Predict initial layout time for each. Then predict which of the two containment variants helps initial render more, and by how much.
Run
cd src && npm install && npm run containment
Expected output:
variant | DOM nodes | initial style | initial layout
no containment | 261011 | 99.5ms | 401.9ms
content-visibility: auto | 261011 | 10.9ms | 7.9ms
contain: strict | 261011 | 89.6ms | 398.4ms
What just happened
content-visibility: auto cut initial layout by 98% — 401.9 ms to 7.9 ms — with an identical
node count, no JavaScript, and one declaration. The DOM was never the problem.
contain: strict did essentially nothing (398.4 vs 401.9 ms). This is the more important half.
The two solve different problems, and conflating them is the most common containment mistake:
| Question | Tool |
|---|---|
| "Most of this is offscreen — may the browser skip it?" | content-visibility: auto |
| "A change inside this box must not disturb the page" | contain: layout (+ size) |
A team that adds contain expecting content-visibility's effect measures no improvement and
concludes containment is useless. The measurement is what prevents that.
Always pair content-visibility: auto with contain-intrinsic-size. Without it, skipped
subtrees measure as zero height: wrong scrollbar, jumping scroll position. contain-intrinsic-size: auto 240px says "assume 240px until you know better, then remember."
Try before continuing
CARDS=200 npm run containment
The advantage should shrink or vanish — everything now fits near the viewport, so there is nothing to skip. Being able to predict that is the checkpoint, not the original number.
Checkpoint
docs/verification.md Checkpoints 1 and 2.