Render Pipeline
Bytes β pixels in 16.67 ms
The browser's rendering engine parses HTML into DOM, CSS into CSSOM, merges into a render tree, calculates layout, paints, and composites β all targeting 60 fps (16.67 ms per frame).
How It Works
The rendering pipeline transforms bytes into pixels through a series of well-defined stages. The HTML parser tokenizes and builds the DOM tree incrementally (streaming β it doesn't wait for the full document). In parallel, the CSS parser builds the CSSOM (CSS Object Model) from stylesheets. These merge into a render tree: only visible elements with computed styles. The layout engine then calculates the exact position and size of every element β processing the box model, flexbox, grid, float, and position rules.
After layout, the browser creates paint records β draw commands like 'fill rectangle at (x,y) with color #fff' β and organizes elements into compositing layers. The compositor thread (separate from the main thread!) rasterizes layers into GPU tiles using worker threads, then the GPU composites all layers into the final frame buffer. This pipeline must complete in 16.67 ms to maintain 60 fps. If your JavaScript takes 100 ms, the pipeline stalls β that's a dropped frame (jank).
The Signal Flow
Key Concepts
A tree data structure representing the HTML document. Each HTML tag becomes a node. The DOM is the live, mutable representation that JavaScript can read and modify. Changes to the DOM trigger re-layout and re-paint.
When multiple CSS rules target the same element, the cascade determines which wins: !important > inline > ID > class > tag. Specificity is the scoring system. The result is a 'computed style' for each property of each element.
The algorithm that turns CSS rules into pixel coordinates. It processes the box model (margin, border, padding, content), resolves flexbox and grid, handles floats and positioning. Layout is expensive β changing one element's size can trigger layout for its entire subtree.
Elements with certain properties (transform, opacity, will-change, position: fixed) are 'promoted' to their own GPU layer. These layers can be transformed and composited cheaply by the GPU without re-painting. This is why CSS transforms animate smoothly β they only affect compositing, skipping layout and paint entirely.
Deep Dive
The 16.67 ms budget
At 60 fps, each frame gets 16.67 ms. But the browser needs ~4 ms for its own overhead (style, paint, composite), leaving your JavaScript about 10β12 ms per frame. If layout takes 5 ms and your JS takes 8 ms, you're at 13 ms β smooth. But add a forced synchronous layout (reading offsetWidth after a DOM change) and suddenly you're at 25 ms β the frame is dropped. Performance tools (DevTools Performance tab) show exactly where each millisecond goes.
Layout thrashing
Layout thrashing happens when JavaScript alternates between writing to the DOM and reading layout properties. Each write invalidates layout; each read forces the browser to recalculate it. Read-write-read-write in a loop can trigger layout hundreds of times per frame. The fix: batch all reads first, then all writes. Or use requestAnimationFrame to defer writes. Libraries like FastDOM automate this batching. This is the single most common cause of JavaScript-induced jank.
Related Specs
Must-know specifications from the Browser Platform layer.
The spec behind every HTML page, form, and browser API. The canonical reference for how browsers actually parse and process HTML.
Every frontend framework (React, Vue, Svelte) ultimately produces DOM operations. Understanding the event model and tree structure prevents subtle bugs.
Every fetch() call and XHR request is governed by this spec. It also defines CORS behavior in detail.
CSS drives all visual layout. Key modules: Grid, Flexbox, Custom Properties, Cascade layers, Container Queries. The snapshot identifies what's stable vs experimental.
JavaScript is the execution model of the web. The spec is the canonical reference for language semantics β closures, coercion, prototype lookup, module resolution, and async scheduling.
Every component framework (React, Vue, Lit, Angular) either compiles to or interacts with these primitives. Shadow DOM is how browsers isolate component internals. Understanding the native model prevents framework lock-in.