Browser Rendering Pipeline — DOM, CSSOM, Layout, Paint, Composite & CRP
Bytes become pixels through DOM, CSSOM, render tree, layout, paint, and composite. The critical rendering path is what blocks first paint. Thrashing and layers explain jank.
- 1Gist
- 2Maps
- 3Q&A
- 4Sandbox
Voice readout needs Web Speech Synthesis in this browser.
Question ladder
L1
What is the order from bytes to pixels?
Answer
HTML to DOM, CSS to CSSOM, render tree, layout, paint, composite.
L2
What is the critical rendering path?
Answer
The resources and pipeline stages that must finish before the first meaningful paint: critical HTML, critical CSS, and scripts or fonts that block the render tree.
L3
What invalidates layout but not a transform animation?
Answer
Width, height, top, and font changes need geometry. A transform or opacity change on its own layer often stays on the compositor.
L4
What is layout thrashing?
Answer
JavaScript reads geometry, writes style, and reads again, so the engine flushes layout on every iteration.
L5
How do you see it in the Performance panel?
Answer
A recording shows repeated Layout or Recalculate Style under the interaction, on the main thread, next to long tasks. Paint flashing and layer borders confirm the guess.
L6
What is the cost of will-change on hundreds of nodes?
Answer
Each promoted layer spends memory. Scroll and composite can get slower even though a single transform looked cheaper.
L7
How does this differ from a sampling profiler lesson?
Answer
This page is which pipeline stage ran. A sampling profiler attributes CPU stacks inside a function. Use the trace's Layout and Paint rows before you reach for a flame graph.
Failure modes
Parser-blocking script
A synchronous script in the head delays DOM construction, so the render tree waits.
Layout thrash
offsetHeight inside a write loop multiplies layout work.
Animating top or width
Every frame pays layout and paint instead of a compositor transform.
Layer explosion
will-change or extra compositing layers exhaust GPU memory and slow scrolling.
Invisible text
A font blocks first text paint. font-display swap shows a fallback and then swaps.
Misconceptions
The DOM is the render tree.
The render tree drops non-rendered nodes and joins computed style. display:none is not a box.
Every CSS change lays out.
Color can paint without layout. Transform can composite without paint. Width does all three.
The Performance panel is a CPU profiler.
It shows main-thread pipeline work and frames. A sampling profiler is a different tool for hot functions.
Interviewer traps
Jumping to React reconciliation or a flame graph.
Name the stage: style, layout, paint, or composite. Stay on the browser pipeline.
Memorizing every CSS property's invalidation bit.
Give the relative cost. Engines differ. Width is layout. Transform is usually composite.
A list of cards animates in
Prefer
Transform and opacity on a few layers
The compositor can move layers without measuring the document again.
- Layout and paint stay quiet during the animation.
- You promote the nodes you actually animate.
- The main thread can stay free for input.
Alternative
Animate top, left, and height
Every frame invalidates geometry and paint.
- The main thread does layout for the whole affected tree.
- Jank shows up as long Layout bars while scrolling.
- will-change on every card spends memory to hide a bad property.
One frame, from bytes
- 1
Parse HTML and CSS
DOM and CSSOM are both required before the render tree. - 2
Render tree
Visible boxes only. display none drops out. - 3
Layout
Geometry. Width, font, and inserting a node come back here. - 4
Paint
Display lists for color, shadow, and text. - 5
Composite
Layers become a frame. Transform and opacity often stop here.
Overview
Bytes become pixels through DOM + CSSOM, render tree, layout, paint, composite. The critical rendering path is what blocks first paint. Style and layout thrashing, and too many layers, explain jank. The compositor explains why transform and opacity animations stay cheap.
This is the browser's frame pipeline. It is not a sampling-profiler lesson and not a load-test lesson. When the question is "which function burned CPU," use a profiler. When the question is "why did this scroll layout three times," stay here. Which OS process hosts Blink is the next page.
Script order relative to a paint opportunity is the event loop. The adjacency is JS event loop, microtasks, and macrotasks. This page owns the stages those tasks invalidate.
Pipeline
Flow
- 1
1. HTML bytes become the DOM
- next2. CSS bytes become the CSSOM
- 2
2. CSS bytes become the CSSOM
- next3. Build the render tree
- 3
3. Build the render tree
- next4. Layout computes geometry
- 4
4. Layout computes geometry
- next5. Paint records display lists
- 5
5. Paint records display lists
- next6. Composite layers to a frame
- 6
6. Composite layers to a frame
Lesson map
Browser Rendering Pipeline — DOM, CSSOM, Layout, Paint, Composite & CRP
Bytes become pixels through DOM, CSSOM, render tree, layout, paint, and composite. The critical rendering path is what blocks first paint. Thrashing and layers explain jank.
Architecture. Architecture
Select a node to see why it exists, or an edge to see the protocol, direction, effect, and consequence.
Mermaid export
flowchart TB a["1. HTML bytes become the DOM"] b["2. CSS bytes become the CSSOM"] c["3. Build the render tree"] d["4. Layout computes geometry"] a -->|1. HTML bytes become the DOM| b b -->|2. CSS bytes become the CSSOM| c c -->|3. Build the render tree| d
| Stage | Input | Output | Invalidated by |
|---|---|---|---|
| Parse HTML | Bytes | DOM | document.write, innerHTML |
| Parse CSS | Bytes | CSSOM | Stylesheet changes |
| Render tree | DOM + CSSOM | Visible boxes | display and visibility rules |
| Layout | Render tree | Geometry | Width, top, font, new boxes |
| Paint | Layout | Display items | Color, shadow, visual properties |
| Composite | Layers | Frames | Transform and opacity on their own layer |
DOM and CSSOM join at the render tree. The diagram stacks them so the card stays one column. Neither tree alone is paintable.
Critical rendering path
The critical rendering path is the minimum dependent chain to the first meaningful pixels: critical HTML, critical CSS, and the blocking scripts or fonts that delay the render tree.
| Tactic | How it helps | Overuse |
|---|---|---|
| Inline critical CSS | First paint does not wait on another stylesheet round trip | Bloated HTML |
defer or async for non-critical JS | The parser is not stuck on a script | Order bugs if you needed sync |
font-display: swap | Text is not invisible until the font arrives | Flash of fallback text |
| Preconnect or preload | The connection or the file starts earlier | Contention with the real critical set |
| Route-level code split | Less script before the first interaction | A waterfall of late chunks |
A synchronous script in the head is on the critical path because HTML parsing stops until it runs. That is a pipeline fact, not a framework preference.
Style and layout thrashing
Geometry reads (offsetWidth, offsetHeight, getBoundingClientRect, scrollTop) can flush pending style and layout. Interleaving them with writes multiplies that cost.
function thrash(els) {
for (const el of els) {
const h = el.offsetHeight;
el.style.height = h + 10 + "px";
}
}
function batched(els) {
const heights = els.map((el) => el.offsetHeight);
els.forEach((el, i) => {
el.style.height = heights[i] + 10 + "px";
});
}The sandbox counts flushes. A read after a dirty write forces one flush. Batched reads happen while the tree is still clean, so the flush count stays at zero until you write.
Press Run. Snippets must be self-contained — no network, files, or native modules.
Layers and the compositor
| Promotion | Why animation gets cheaper | Cost |
|---|---|---|
transform or opacity | Often compositor-only | Memory for the layer's tiles |
will-change: transform | Hint to promote before the first frame | Over-promotion wastes GPU memory |
| Video, canvas, fixed, sticky | The browser may layer them already | More compositing work |
What if you choose the other? Animating top, left, or width lays out and paints every frame. Animating transform often composites only. Blind will-change on hundreds of nodes spends memory and can make scroll slower.
Performance panel, as a pipeline
- Record the interaction or the load.
- Look for long tasks that block the main thread.
- Read Recalculate Style, Layout, Paint, and Composite Layers.
- Repeated Layout during scroll is thrashing or expensive CSS, not a mystery.
- Frames tell you whether the compositor or the main thread is the busy one.
- Paint flashing and layer borders are the overlays that confirm it.
Interview line: jank is main-thread work (script, style, layout, paint) or compositor and GPU overload. Measure the row before you guess the function.
What invalidates what
| Change | Layout | Paint | Composite |
|---|---|---|---|
color | No | Yes | Maybe |
width or height | Yes | Yes | Yes |
Animate transform | No | No | Yes |
| Add a DOM node | Yes | Yes | Yes |
| Scroll, typical | Often no, the compositor scrolls | Sometimes | Yes |
The exact matrix is engine-specific. Interview for relative cost, not a memorized property table.
Flow
- 1
1. JS reads offsetHeight
- next2. Pending layout flushes
- 2
2. Pending layout flushes
- next3. JS writes style.height
- 3
3. JS writes style.height
- next4. The next read flushes again
- 4
4. The next read flushes again
- next5. Batch the reads, then write
- 5
5. Batch the reads, then write
Interview Q&A
What is the critical rendering path?
Answer
The dependency chain of resources and pipeline stages that must complete before the first paint of meaningful content.
Why can transform animations be smoother?
Answer
They often avoid layout and paint. The compositor updates the layer transform on its own thread.
How do you detect layout thrashing?
Answer
A performance trace with repeated Layout forced by script that reads geometry between style writes. Fix it by batching reads, then writes.
Why do DOM and CSSOM both have to exist?
Answer
The render tree is styled boxes. HTML without CSS does not know which rules apply. CSS without a DOM has nothing to match.
Does color change layout?
Answer
No. It invalidates paint. Width invalidates layout, paint, and composite.
What does font-display swap trade?
Answer
You get text sooner with a fallback face, then a swap when the web font arrives. The alternative is invisible text on the critical path.
Where does a Service Worker sit on this path?
Answer
It can answer the navigation from Cache Storage before the network, so HTML bytes arrive sooner. It does not skip layout or paint. Those still run in the renderer.
Why not will-change everything?
Answer
Each layer is memory. A page of promoted cards can make composite and scroll more expensive than the layout you were avoiding.
Pitfalls
- Reading
offsetHeightin a loop that also writesstyle. - Treating the Performance panel's Layout row as a CPU flame graph.
- Inlining the entire stylesheet and calling it critical CSS.
- Explaining a compositor animation with React render counts. Different pipelines.
A click handler sets el.style.width, then reads el.offsetHeight, then sets el.style.transform. Which steps flush layout, which can stay on the compositor, and what would you reorder?