With structure and style in place, the story starts to unfold. (Read Part 3 to see how we got here)
The browser takes the scripted DOM and styled elements and starts arranging them spatially: calculating layout, painting each pixel, and layering them with precision.
This is the visual crescendo: where code turns into form, motion, and color.
It’s the final act before the audience sees the outcome.
Let’s walk through how layout, paint, and compositing work together to turn code into pixels.
- Layout Begins: Calculating Geometry
- Paint Club: Painting the Pixels
- GPU of Thrones: Compositing Layers
With the DOM and CSSOM ready, the browser builds the render tree. It only includes elements that affect what’s displayed on the screen.
If an element has display: none, it’s ignored. But if you use opacity: 0 or visibility: hidden, the element stays in the render tree, it just won’t be visible on screen.
Next comes layout (also known as reflow), where the browser figures out the exact size and position of every node in the render tree. It determines whether each element is block or inline, how wide and tall it should be, and where it fits relative to other elements.
This phase is performance-sensitive. When layout-affecting changes, like adjusting width, font-size, or inserting new elements, occur the browser recalculates geometry. Sometimes these updates force other elements to adjust too.
A common pitfall is animating layout-affecting properties like height, top, width, margin, etc. Expanding a dropdown by animating its height from 0 to 100px over 1000ms might seem harmless, but it forces the browser to reflow and repaint on every animation frame, around 60 times per second, all on the main thread. On heavier pages or low-end devices, this can cause jank or dropped frames.
That doesn’t mean increasing height is always bad. A one-time layout update, like showing a dropdown on click, is fine. The problem is when layout is recalculated continuously during animations.
To avoid that, prefer GPU-friendly properties like transform and opacity. They don’t trigger reflows and can be composited efficiently without blocking the main thread. For instance, use transform: scaleY instead of animating height.
See it Yourself
Open Chrome DevTools > Rendering tab > Enable "Layout Shift Regions" to highlight areas recalculated during layout.
Once layout settles the size and position of everything, the browser moves on to painting, turning the render tree into actual pixels.
But the browser doesn’t paint directly to the screen. Instead, it paints onto off-screen buffers called bitmaps. Each layer gets its own bitmap, and all the visual elements inside that layer are drawn onto it: borders, text, backgrounds, shadows, images, etc.
This step is called rasterization: converting styled elements into pixel data. Once rasterized, the bitmap becomes a visual snapshot of that layer, ready to be sent to the GPU for compositing.
Since the browser paints by layers, it doesn’t need to redraw the whole page for every change. Instead, it updates only the bitmaps for the affected layers. This makes minor UI updates much faster.
See it Yourself
Open Chrome DevTools > Rendering tab > Enable "Paint flashing" to highlight areas that get repainted.
After painting, the browser hands the resulting bitmaps to the GPU for compositing, the final step where everything gets assembled on screen.
The GPU blends and stacks these painted layers in the correct order, applies transforms like scaling or rotation, and positions them accurately. It doesn’t repaint or reflow anything. It just moves pixels around using already-rasterized content.
Some elements get their own layers by default: position: fixed, <video>, and 3D transforms. Others can be promoted when you use properties like transform, opacity, filter, or will-change. These hint that an element might benefit from GPU compositing, but promotion isn't guaranteed. The browser decides based on cost and benefit.
You can use will-change to suggest an element might change soon, prompting the browser to prepare. But it's a hint, not a command.
📌 Note: More layers aren’t always better. They use extra GPU memory and add compositing cost. Promote only if you see jank. Profile before overriding the browser’s defaults.
See it Yourself
Open Chrome DevTools > Layers tab to see what all areas of your website get a different layer.
Wrap-up
Code has become pixels. Your page is now visible (finally)!
In the next and final part, we’ll step backstage and see how browsers schedule all these operations, from networking to rendering, while keeping things smooth, interactive, and fast. Stay tuned!