Understanding the critical rendering path, rendering pages in 1 second
A popular metric commonly used in performance measurement and evaluation, is the total page load time. This metric, obviously, has its importance when evaluating performance, as it states the full download time, to get your website and all of its assets.
But from a user’s point of view, more important benchmarks arise, despite the fact that the full download time of a page is still important, the user is much more aware of the time it takes for the page to become usable, or the time it takes to render the main content, so that he can access those first glances of information.
Some usability metrics, that were initially defined by Norman Nielsen, state that, after only one second with no response, there’s a mental context switch in our brains, that’s the moment when we stop focusing in the task at hand and start thinking about other subjects.
0–100 ms — Instant feel, constant flow;
100–300 ms —Slight percetible delay;
300–1000 ms — Loss of task focus, perceptible delay;
1 s+ — Mental context switch;
10s+ — User leaves;
But we don’t need to fully load a page in one second, what we need to do, is to get to the most important content, to get some usable piece of information to the user in one second, in order to maintain flow and give a feel of instant execution, an instant experience.
In order to achieve this we first need to fully understand what’s needed for a browser to render content to the screen.
How does the browser rendering engine work?
In order to render content the browser has to go through a series of steps:
1. Document Object Model(DOM)
2. CSS object model(CSSOM)
3. Render Tree
1. Document Object Model
To process a html file and get to the document object model event(DOM) the browser has to go through 4 steps:
1. Convert bytes to characters
2. Identify tokens
3. Convert tokens to nodes
4. Build DOM Tree
This entire process can take some time, specially if there is a large amount of HTML to process. This means that the initial file size of your DOM tree will have a performance cost.
In order to measure the full time needed for this process, you can record a timeline on chrome devtools while your page is loaded.
When this process is finished the browser will have the full content of the page, but to be able to render the browser has to wait for the CSS Object Model, also known as CSSOM event, which will tell the browser how the elements should look like when rendered.
2. CSS Object Model
Just as with HTML, the CSS rules need to be converted into something that the browser understands, so these rules go through the same steps as the document object model.
1. Convert bytes to characters
2. Identify tokens
3. Convert tokens to nodes
4. Build CSSOM
In this stage the CSS parser goes through each node and gets the styles attributed to it.
CSS is one of the most important elements of the critical rendering path, because the browser blocks page rendering until it receives and processes all the css files in your page, CSS is render blocking
3. The Render Tree
This stage is where the browser combines the DOM and CSSOM, this process outputs a final render tree, which contains both the content and the style information of all the visible content on the screen.
This stage is where the browser calculates the size and position of each visible element on the page, every time an update to the render tree is made, or the size of the viewport changes, the browser has to run layout again.
When we get to the paint stage, the browser has to pick up the layout result, and paint the pixels to the screen, beware in this stage that not all styles have the same paint times, also combinations of styles can have a greater paint time than the sum of their parts. For an instance mixing a border-radius with a box-shadow, can triple the paint time of an element instead of using just one of the latter.
1. Inlined scripts above the css files ‘<link>’ in the ‘<head>’;
2. Async scripts.
Optimizing the critical rendering path
Understanding the critical rendering path
How would we optimize this?
First of all, we need to make our critical assets as small as possible by minifying and compressing both the html and css. We can further optimize this resources by making use of html and css obfuscation. Obfuscation is the process of going through all of your class names in both the html and css, and converting something like ‘.header__nav — fixed’ into ‘.a_123’ which can help you squeeze some more bytes out of your rendering path.
Some tools available:
Next step: optimising css delivery
With our resources optimized we need to get them to the client as fast as possible. A good strategy is to inline our css, so that we can get it to the client with the first html request, allowing the browser to get to the CSSOM event with only one request.
But in this case our first request would get a little too big with 46kb. The page could still render faster but in some cases a big initial request can make things worse.
This can be tricky specially when dealing with responsive websites (should we inline responsive grids?, should we inline for mobile and desktop? Always test it first!)
A good strategy is to inline only the css for the header and the main module of the page, and downloading the remaining css async. You can hide the unstyled content of the page, while the client waits for the reamining CSS, this is made to avoid the flash of unstyled content.
If you’re going down this path and you’re using web fonts, it’s an absolute must to have your webfonts async. You don’t want to render the styles immediately and have your users waiting on the fonts to see the text, which is probably the most important part of your content.
More on async webfonts:
Achieving the 1s render
So let’s say that we’ve done all the optimizations mentioned above, will our page render in one second?
…the server can send up to 10 TCP packets on a new connection (~14KB) in first roundtrip, and then it must wait for the client to acknowledge this data before it can grow its congestion window and proceed to deliver more data.
Due to this TCP behavior, it is important to optimize your content to minimize the number of roundtrips required to deliver the necessary data to perform the first render of the page. Ideally, the ATF (above the fold) content should fit under 14KB — this allows the browser to paint the page after just one roundtrip…
Mobile Analysis in PageSpeed Insights
PageSpeed Insights analyzes a page to see if it follows our recommendations for making a page render in under a second…
In order to make our page render in 1s we need to make our critical html and css fit in approximately 14kb. If we follow the logic mentioned above, this would be the header and the main module of the page.
If you’ve managed to get through the whole process and made all the optimisations mentioned above, congratulations you should now have devivered an instant experience.
Understanding how a browser works and how it gets the content needed to render the page, is essential for optimising the critical rendering path.
Also simplicity in design and thinking about performance since day one, are essential elements to achieve the holy grail of the instant experience. We cannot deliver the main content of the page in one second if we expend that budet with just the header or with extremely complex styling.
Still it’s always better to render something as fast as possible to the page, than having your users staring at a blank screen.
We’ll talk again when HTTP2 usage goes mainstream and everything changes again!