How browser rendering works

by L. David Baron

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

This is the story of how Web browsers work. Really, it's just about how a part of Web browsers work: what I'll call the rendering pipeline. There are many other interesting parts of Web browsers. Browsers download resources from the network and do crytography. Browsers parse HTML into a DOM tree (or content tree), which is just an in-memory representation of the tree structure that the HTML markup represents. Browsers execute JavaScript, which is a programming language, and allow that JavaScript to call APIs that are part of the Web platform.

What I call the rendering pipeline is about what happens between that DOM tree and the screen. This is the story of how CSS style sheets are processed, how the DOM tree is combined with those style sheets to build a rendering tree (or box tree), how the positions and sizes of the nodes in that tree are calculated, and how the result is painted to the screen. It is the story of how all of those pieces are optimized so that it's possible to build efficient applications.

This story is written for people who develop applications on the Web platform. While the Web platform was originally designed for documents, it has evolved into a platform for applications. My hope is that understanding how the rendering pipeline works will help authors understand how to build more efficient applications: applications that run faster, respond faster, and use less power.

Before I begin, though, I should make a brief note about my perspective. I work on Gecko, the layout engine used in Firefox and other Mozilla products, which is one of the three major layout engines for Web browsers being actively developed today. The other two are WebKit, which is used in Safari and Chrome, and Trident, which is used in Microsoft Internet Explorer. Many of the things I say here apply across layout engines, but quite a few are specific to Gecko, and I don't always know which are which, though I attempt to be clear when I do.

The rendering pipeline without optimization

So let's start by walking through the parts of the rendering pipeline. This diagram illustrates the rendering pipeline as a whole, but let's go through it piece by piece.

Parsing

HTML is a serialization of a tree structure. The goal of parsing is to convert the HTML file's text back into that tree structure. This tree, which we call the DOM tree or the content tree, stays in memory as long as we display the page. It's one of the most important data structures in the rendering pipeline, and it's the one that script interacts with directly.

Let's start with a simple example of an HTML document that represents a particular tree structure:

html head body title "Web p..." div h1 "Web p..." svg line g ellipse text "This..."

Style computation

Rendering tree construction

Layout

Painting

Optimizations

TODO: Unoptimized view of world: redo everything for each DOM or style change

TODO: (Alternate view: cache nothing, and redo everything each repaint)

TODO: optimizations can and do change

Optimization: skipping stages of the pipeline

<script>
  div.setAttribute("data-rating", "excellent");
</script>

Browsers can check whether there are selectors that care about this attribute, and as a result not even compute style.

<script>
  div.setAttribute("data-rating", "excellent");
</script>
<style>
  #list div[data-rating="excellent"] {
    background: yellow; color: black;
  }
</style>

Now there are selectors, so we have to rerun selector matching. But if the div isn't inside an element with id="list", nothing changed.

<script>
  div.setAttribute("data-rating", "excellent");
</script>
<style>
  div[data-rating="excellent"] {
    background: yellow; color: black;
  }
</style>

Now the rerunning of selector matching actually makes a new rule match that didn't before.

Or maybe nothing changed:

p { background: yellow }
p:hover { background: yellow }

TODO: write

Optimization: skipping part of a stage

TODO: describe stage-specific optimizations

Skipping part of frame construction / rendering tree construction:

<script>
/* likely Gecko-specific */
function flush_frames(elt)
  { getComputedStyle(elt, "").color; }
var start = Date.now();
for (var i = 0; i < 10000; ++i) {
  test_elt.style.display = "none";
  flush_frames(test_elt);
  test_elt.style.display = "";
  flush_frames(test_elt);
}
var time = (Date.now() - start);
</script>

Skipping part of reflow:

<script>
function flush_layout(elt) { elt.offsetTop; }
var start = Date.now();
for (var i = 0; i < 10000; ++i) {
  test_elt.style.fontSize = "1px"; /* or width */
  flush_frames(test_elt);
  test_elt.style.fontSize = ""; /* or width */
  flush_frames(test_elt);
}
var time = (Date.now() - start);
</script>

Skipping part of painting:

coalescing multiple runs (both general and stage-specific)

TODO: talk about screen refresh rates

Authors might change the same element twice:

element.style.position = "absolute";
element.style.overflow = "auto";

Authors might make changes where the work needed to handle one subsumes the work for the other:

element.style.backgroundColor = "blue";
element.parentNode.style.opacity = "0.8";

Browsers don't actually process the changes until:

some things that flush style / frame construction:

some things that flush layout:

DO NOT DO THIS:

for (var i = 0; i < n; ++i) {
  var photo = document.getElementById("photo" + i);
  var label = document.getElementById("label" + i);
  label.style.top = photo.offsetHeight + "px";
}

These can sometimes be hidden in frameworks.

animations

low-level optimizations

TODO: Is this even a good section title?

TODO: better algorithms, better parallelism (e.g., GPU)

TODO: figure out how I want to talk about graphics acceleration (e.g., if it fits in this structure). Talk about:

Further material

Since I haven't made much progress on writing this so far, it's worth noting that one of my main sources of the content above is a talk I gave at SXSW on 2012-03-11 into written form. This talk was /Fast CSS: How Browsers Lay Out Web Pages/: slideshow, all slides, audio (MP3), Session page, Lanyrd page.