Critical Rendering Path is a process a browser follows to convert the code into what a user sees as a website. A proper optimization of this process helps to reduce the page load time.

In this article, you will learn how a single frame is rendered.As this article explains the very basics of what happens in the browser's background, you've probably applied some techniques built on top of this knowledge, but there's a high chance that you've never asked yourself “why”.

So now, let’s ask ourselves this question: What are the intermediate steps that browsers take to render the webpage I've coded?

Document Object Model

The very first thing that browsers do, usually only during initial page load, is, of course, parsing HTML and transforming it into DOM (short for Document Object Model) that we all know so well. It's an interface to the outside world, such as JavaScript.

An important thing to note is that this process is paused when parser encounters JavaScript due to the possibility of new DOM elements being appended during execution.

You may also like: What is a boilerplate? Meaning, history and examples

This delays the first meaningful paint until the script is both fetched and run. Use an `async` attribute on a tag to download the script in the background and a `defer` attribute to delay its execution until HTML parsing is completed.

In Chrome's Developer Tools performance tab, this process will be color coded with blue.

CSS Object Model

Next, CSS is parsed and transformed into CSSOM. Rendering is blocked until this process is finished. It's important to note here that if not done efficiently, it can have negative consequences.

If your Javascript interrupts the CSSOM from being built, your users will see blank page longer than they should.

In Chrome's Developer Tools performance tab this process will be color coded with blue.body {

 font-size: 14px;

}

When you look closely, you’ll notice that the `font-size` property was set only on a body, yet it propagated to all other elements. This is where the “Cascading” part in “Cascading Style Sheets” comes from!

Constructing render tree

Browsers combine DOM and CSSOM to construct a Render Tree, which is a visual representation of the document. The purpose of this tree is to enable painting the contents in the correct order.

Each element is called "a renderer" and represents a rectangular area which usually corresponds to the node's CSS box. Real positions and dimensions of the area are unknown at this point.

Non visual elements won’t be inserted into the render tree (e.g. "head"). Also, any elements with display attribute set to "none" will not appear in the tree (this doesn’t apply to the visibility set to "hidden").

In Chrome's Developer Tools performance tab, this process will be color coded with purple.

Layout

During Layout (aka Reflow), the renderers created in the previous step calculate their own geometries – positions and sizes. This process is recursive and proceeds left-to-right and top-to-bottom throughout the document.

Some exceptions exist, such as HTML tables, which require more than one pass. The coordinate system is relative to the root renderer. Its position is always 0,0 and its dimensions are the visible part of a browser (viewport).

Worth checking: Constate Library - alternative to global state of the app management

Have you ever wondered what the viewport meta tag, which you probably add to your every app, actually does?

<meta name="viewport" content="width=device-width, initial-scale=1">

It sets the size of root renderer to the actual device width. Otherwise, it would be most of the time set to 1920 x 1080. This, as you probably know, would render a huge page on a small device requiring a user to zoom in and pan the screen.

Layout is the most expensive process in a pipeline. It’s usually the first place to search for performance optimizations. When Javascript reads from and writes to DOM too often, it can lead to so called "layout thrashing" due to "forced synchronous layout".

In Chrome's Developer Tools performance tab, this process will be color coded with purple.

Paint

Now we need to transform our vector geometries calculated in the previous step into individual pixels. This process is actually composed of two tasks: creating a list of "draw calls" and rasterization (filling in pixels). It involves drawing out colors, images, borders, outlines, and text.

Drawing is typically done onto multiple layers. Some browsers, such as Chrome, use multiple rendering threads so they can draw to them simultaneously in order to improve performance, but it’s not something that we, the developers, can control.

In Chrome's Developer Tools performance tab, this process will be color coded with green.

Compositing

At this point, we have a set of multiple drawn layers that will be drawn onto the screen in the specific order. This is especially important for layers, which overlap each other, to avoid mistakes where one element would incorrectly appear on top of another.

Might be interesting: How to combine React Query & Constate? Practical guide

Everything up until this point has happened on CPU. Now, the drawn layers are sent to GPU, in a form of small rectangular tiles, which render the frame onto the screen. In Chrome's Developer Tools performance tab, this process will be color coded with green.

You can easily see layers created by your own app in Chrome Dev Tools by selecting “Layer borders” in “Rendering” tab. On the attached image, you can distinguish both layers and tiles created in the rendering phase. The former is colored in orange and latter in light blue.

Wrap up

These are all the steps browsers have to take to render your webpage, which is called the Critical Rendering Path. Optimizing these steps will help you reduce the page load time, which is important for both website’s SEO and the user’s bounce rate.

If you liked this article, make sure to check out also: How to use typescript record utility type.