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
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.
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;
}
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.
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.
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.
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>
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>
.
Image optimization is one of the most commonly recommended performance optimizations and provides quick "wins" from a pagespeed perspective.
<img src=""
and queues the referenced image resource.<img>
, a network request is created and the resource download starts.The process of painting and compositing images is a fairly expensive task. The painting process of an image is incremental.
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.
<head>
.<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.