Go Back

How to optimize browser tasks related to painting and the render tree

Author: Ben Bozzay

The process for displaying visual content to the user takes place over a series of tasks.

The general flow of tasks is as follows:

Recalculate Style > Layout > Update Layer Tree > Paint > Composite Layers

Recalculate Style

Similarly to the HTML Parser, the end result of CSS parsing (the Parse Stylesheet task) is the formation of the CSSOM, which is another logical tree.

It is a tree containing all CSS selectors and relevant properties for each selector.

CSSOM Tree

When computing the final set of styles for any object on the page, the browser starts with the most general rule applicable to that node and then recursively refines the computed styles by applying more specific rules. Rules "cascade down" and this is why CSS is called cascading stylesheets.

A primary part of CSSOM construction time is the time it takes to compute these styles with inheritance applied.

CSS rules can be inherited from parent elements and overridden on child elements. For example, we can add font-size to the <body> parent node and our <h2> should inherit that font-size.

// style.css
// The only styles referenced in our Document

html {
  font-size: 5px;
}
body {
  font-size: 10px;
}

Inheritance

Our paragraph tag inherits the closest parent's font-size, which is the body tag in this case The browser also provides a user agent stylesheet, which provides default styling for certain elements. Usually stylesheets are comprehensive enough to override all the rules in this stylesheet.

The CSSOM contains styles from multiple stylesheets. In this case, it contains styles from the user agent stylesheet and our style.css file.

...
  <link rel="stylesheet" href="/dist/css/style.css" />
  <link rel="stylesheet" href="/dist/css/style_2.css" />
</head>

If the stylesheets use the same specificity when targeting the node, the rule from the stylesheet that is loaded later takes priority.

Layout

The layout (or reflow) task involves calculating the position and dimensions of all elements on the screen.

Since HTML Nodes can be nested, these dimensions also are relative to parent nodes or the window. Each element will have explicit or implicit sizing information based on the CSS that was used, the contents of the element, or a parent element.

Render Tree

The render tree (layout tree) determines what is visually painted on the screen. It's a combination of HTML nodes from the DOM Tree and CSS nodes from the CSSOM.

The main thread walks through the DOM and computed styles and creates the layout tree which has information like x y coordinates and bounding box sizes.

The Render Tree is the combination of visually rendered nodes from the CSSOM and DOM.Rendering can occur incrementally.

Some tags, like the <head>, <script>, <title> tags are not visually displayed to the user and the render tree doesn't include them.

Incremental Rendering

Like the DOM, the render tree is built incrementally and will update when the DOM or CSSOM changes.

The painting process starts when the render tree contains one visually rendered HTML node, like an <h1> within the <body>. The render tree updates with new nodes discovered by the DOM parser and this triggers a painting task.

Incremental rendering also occurs with CSS. When the CSSOM updates, so does the render tree.

Loading styles at the end of the <body> shows a brief flash of unstyled HTML as the render tree updates with newly discovered nodes from the CSSOM. Since the painting process has already started,

<body>
  // black h1 is painted on the screen
  <h1>Heading</h1>
  <script>
    // Block DOM construction
    delay(3000)
  </script>
  // h1 turns blue after 3 seconds
  <style>
    h1 {
      color: blue;
    }
  </style>
</body>

Intentionally Blocking Rendering

Incremental rendering can be controlled so that above-the-fold content is pre-formatted and the user won't see such an obvious flash of un-styled content.

The DOM Parser evaluates the <head> before HTML nodes in the <body>. The <head> isn't visually rendered or included in the render tree.

Since the render tree needs visually rendered nodes from the DOM, painting can't start until the first html node within the <body> is parsed and attached to the render tree.

<html>

  // Not Visually Rendered
  <head>
    <style>...</style>
    <link rel="stylesheet" src="style.css">
    <script>...</script>
    <title>Title that appears in the browser tab</title>
    <meta name="description" content="Meta information for search results pages">
    // Image thumbnail that displays when shared on social media
    <meta property="og:image" content="image.png" />
  </head>

  // Visually Rendered
  <body>
    <h1>Heading</h1>
  </body>
</html>

Placing styles within the <head> pre-loads the render tree with nodes from the CSSOM. Then, once HTML nodes are discovered and added to the render tree, the subsequent CSS rules are already attached and the painting process starts.

If you want to avoid a flash of unstyled content for content in the initial view (above the fold), place critical styles within the <head></head>. Non-critical CSS could be referenced outside of the <head>.

Images

Image optimization is one of the most commonly recommended performance optimizations and provides quick "wins" from a pagespeed perspective.

Image lifecycle (TBD)

  1. The speculative parser "looks ahead" at any linked resources in the document and queues them for download. In this case, the parser looks for <img src="" and queues the referenced image resource.
  2. When the DOM parser discovers the <img>, a network request is created and the resource download starts.
  3. The DOM Parser continues discovering other HTML Nodes while the image is downloaded (the download is non-blocking)
  4. Most modern browsers use a separate rasterizing thread (not the main thread) to decode the image.
  5. Once the image download finishes, Update Layer Tree > Paint > Composite Layers tasks occur on the main thread.
  6. When rasterizing completes, tasks related to displaying the image occur on the main thread: Layout, painting, calculating rendering layers

Painting Images

The process of painting and compositing images is a fairly expensive task. The painting process of an image is incremental.

Indirect and direct performance impacts

  1. Resource downloads occur in parallel, but some connections and servers might limit the number of simultaneous downloads. This means that images could delay the downloading of other critical resources, like JS included before the closing body tag.
  2. Images are downloaded even when not seen by the user, resulting in wasted data on mobile networks.
  3. After an image finishes downloading, the browser immediately tries to paint the image. If multiple images are downloaded simultaneously, the speed at which a single image is painted is slowed down.

Painting time with multiple images

When a document contains multiple high resolution images, the overall paint time of a single image is increased.

The painting speed significantly improves when the document contains only one image.

Summary

  • The render tree is a logical tree containing the visually painted nodes from the DOM and CSSOM trees.
  • The render tree can be constructed incrementally and the browser will attempt to render changes to the render tree when the main thread is available.
  • JavaScript and CSS critical for the rendering of above-the-fold content is loaded in the <head>.
  • Placing critical CSS and JS in the <head> (a node that isn't part of the render tree) blocks rendering until the render tree contains the HTML and CSS nodes required to render the initial content.
  • The Layout task involves calculating the position of elements on the screen.
    • Element positions are calculated relative to other nodes in the document.
  • Tasks associated with displaying an image can slow down the overall rendering performance of a page.
    • Uncontrolled image downloads can use significant data on mobile.
    • Multiple simultaneous image downloads can slow down the download speed of critical resources, like JavaScript, CSS, or images that display above-the-fold (the initial view).
    • The browser might attempt to paint multiple image simultaneously, which slows down the paint time of each image.
    • Tasks associated with rendering images can clog the main thread, which delays other critical tasks.