Bytes to boxes
Parse, DOM, CSSOM, render tree, layout, paint, composite. Seven words that explain most of what you will ever debug about rendering, and one of them explains why some animations stutter.
The parser turns bytes into tokens and tokens into a tree of nodes: the DOM. Stylesheets go through the same treatment and produce the CSSOM. Neither is your source file, both are the browser’s interpretation of it, so a missing closing tag does not error but does produce a tree you did not write. You will see that happen for yourself in the next lesson.
The render tree is the two of them combined, minus everything invisible. An element with display: none is in the DOM and absent from the render tree. An element with visibility: hidden is in the render tree and still occupies space. That single distinction accounts for a surprising share of layout bugs, and for the classic interview question about the difference between the two.
Layout works out where every box goes and how big it is, sometimes called reflow. Paint fills in the pixels for each box. Composite stacks the resulting layers, usually on the GPU. Each stage depends on the one before it, so forcing an early stage forces everything after it too. That is the cost model, and it fits in one sentence: the earlier the stage you disturb, the more work you have caused.
This is one reason transform and opacity are the two properties worth animating. They can skip straight to compositing, the browser already knows where the box is and what it looks like, it just draws the existing layer somewhere else. Animating left or width instead drags the whole pipeline through layout on every single frame, which is sixty layouts a second, so your animation stutters on a phone and not on your laptop.
Use the instrument below in predict-first mode. Guess which stages light up before you press Check. Get box-shadow wrong, because many people does, it skips layout but is expensive to paint, which is a different problem with a different fix. Getting these wrong here costs you nothing. In production, the same mistake can turn into a long debugging session around an animation that simply feels slow.
What one property costs
The top two rows run once, as the page arrives. The bottom row is the part that can be made to run again, sixty times a second, by a single line of CSS.
Press a property to see which stages the browser has to redo. Click any stage to find out what it actually does.
A and C have closed the gap. B is not laid out, because B is not there.
- div.row
- span A
- span B: absent
- span C
display: none is the only way to leave the render tree. Nothing about the element is measured or painted.
A caveat worth holding: this is the classic model, and it is still the right one to think with, but modern Chrome’s renderer is more complicated than seven boxes in a row, it parallelises, it caches, and it sometimes skips work you would expect it to do. The model is a good predictor, not a description of the source code. When the model and the Performance panel disagree, the Performance panel is right.
Worth reading
- RenderingNG: the next-generation rendering architecture ↗, Where the simple seven-stage model stops being literally true, from the team that rewrote it.
You should now be able to
- Describe the pipeline from markup to painted pixels
- Say which stages a given CSS property forces the browser to redo
- Explain why a style change can cost more than a colour change
- Say what the render tree leaves out and why
Loading…