awesome-everything RU
↑ Back to the climb

Browser & Frontend Runtime

Invalidation, dirty bits, and contain

Crux How CSS property changes propagate through the pipeline, what controls the blast radius, and how contain/content-visibility isolate the damage.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 14 min

You change one class on one element and the browser re-paints a thousand elements. You change a different class on the same element and nothing else moves. The difference is which pipeline stage the property invalidates — and whether anything downstream can escape.

The invalidation rule

Changing a CSS property invalidates one or more pipeline stages. Everything from that stage down must re-run.

CSS changeInvalidatesCost
width, height, top, leftLayout (+ paint + composite)High
background-color, colorPaint (+ composite)Medium
transform, opacity (on own layer)Composite onlyLow
filter: blur(...)Paint (+ composite)Medium–High

csstriggers.com publishes a per-property map. Learn the cheap ones (transform, opacity, filter on a promoted element) and the expensive ones (anything that affects flow).

How dirty bits propagate

Dirty-bit propagation rules

  • Style flags flow down the DOM tree — a class change on a parent dirties all descendants whose selectors match.
  • Layout flags flow down the box tree — a width change on a parent may dirty siblings if their position depends on it.
  • Paint flags are scoped to the paint layer — a paint-affecting change on a layer invalidates that layer’s bitmap; sibling layers with their own bitmaps are unaffected.
  • Composite is always dirty-free — it works from already-rasterised tiles and only re-runs the GPU draw call.

Rule: dirty bits flow DOWN the dependency graph, never UP.

If you can isolate your changes to an independent subtree, the invalidation stops at the isolation boundary.

CSS Containment: capping the blast radius

CSS Containment gives you a knob to limit how far invalidation propagates.

  • contain: layout — “this element’s layout cannot affect its ancestors.” If a child resizes, the parent’s siblings do not need to re-layout.
  • contain: paint — painting is contained inside the box (overflow clipped). The browser can skip painting it entirely when it is off-screen.
  • contain: strict — combines layout, paint, and size containment.

The newer content-visibility: auto goes further: it tells the browser to skip the element entirely (no style calc, no layout, no paint) when it is off-screen. Combined with contain-intrinsic-size (which gives the browser a placeholder size), it lets a page with thousands of below-the-fold elements render in milliseconds because only on-screen elements pay the cost.

These are the modern “free wins” for any page rendering large lists, infinite scroll feeds, or long-form content.

Edge cases

Fonts and FOIT/FOUT. A web font is a pipeline input often overlooked. The font starts loading when the CSS parser sees a font-family backed by a @font-face with a src. Until the font arrives, the browser either shows text in a fallback font (FOUT — flash of unstyled text) or hides text (FOIT — flash of invisible text). The font-display property controls this: swap shows the fallback immediately then swaps; optional uses the fallback if the font hasn’t arrived within ~100 ms; block hides text for up to 3 s. When the loaded font swaps in, the browser re-runs style recalc and layout, because font metrics change text width, which changes box sizes. On a large text block this swap is visible as frame jank 200–500 ms after first paint.

Images and CLS. An image loading without explicit width and height forces a re-layout when it loads: the image box was 0×0, now it is the actual size, and everything around it shifts — the main cause of CLS regressions. The fix is to set explicit width/height in HTML or use aspect-ratio in CSS; the browser reserves the space up front, and the image load becomes only a paint invalidation, not a layout one. Modern loading="lazy" loads off-screen images lazily, saving bandwidth, but still requires pre-declared sizes to avoid layout shift when the image enters the viewport.

Quiz

Which property change invalidates only the composite stage (no layout, no paint)?

Quiz

You add `contain: layout` to a card component. A child element inside it resizes. Which elements need to re-layout?

Quiz

A page uses `content-visibility: auto` on 10 000 below-the-fold list items. What happens during first paint?

Recall before you leave
  1. 01
    Which pipeline stages does changing `width` invalidate?
  2. 02
    What does `contain: layout` tell the browser?
  3. 03
    What is the mechanism behind `content-visibility: auto`?
Recap

Every CSS property change invalidates exactly one or more pipeline stages; dirty bits then flow downstream. width invalidates layout, which forces paint and composite to re-run. opacity on a promoted element invalidates only composite — which is why it is “free.” CSS Containment (contain: layout, contain: strict) stops the invalidation blast at a boundary. content-visibility: auto takes this further: off-screen subtrees are entirely skipped (display-locked), turning a 1200 ms first-paint into 10 ms for long pages. Images without declared dimensions cause layout invalidation on load, which is the root cause of most CLS regressions.

Connected lessons
appears again in162
Continue the climb ↑Compositor layers: promotion, overlap, and GPU memory
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.