Csaba Palfi, Dec 2016
Most web performance recommendations are simple to put into practice. Minifying assets or optimizing images is a matter of configuring some basic tooling.
This post is about eliminating render blocking resources and prioritizing above-the-fold content. These practices enable optimized (progressive) rendering of your web pages.
Do you have the problem?
Do you fail the PageSpeed Insights rule below?
Hint: use ngrok to run PageSpeed Insights against localhost or a private network.
Is your Speed index, Start Render and Visually Complete times too high? Ideally your Visually Complete time should be less than a second.
(See the Details tab on the results page for the Visually Complete time.)
Chrome Developer Tools
Enable throttling (e.g 2G or 3G) in the Network tab then go to your page. Are you staring at a blank screen for seconds? (Be sure to start from
about:blank to really see how long it takes for rendering to start).
You can also look at the screenshots/filmstrip in the Timeline tab.
How CSS resources can block rendering?
It's important to understand the critical steps that need to happen before a single pixel can be painted on the screen. The browser:
- parses your HTML into the DOM tree and your CSS into a CSSOM tree
- these are combined into a render tree that only contains the visible DOM content
- the layout and paint steps depend on the render tree which depends on the CSSOM - nothing can be put on the screen before that's ready
When the browser encounters a link tag for a stylesheet it'll have to go and fetch it as it's needed for building the render tree. Sometimes that CSS file is your bundle containing the styles for your whole page (maybe even the whole website).
Your users could be waiting for the styles for something that's not even on the screen! (i.e. below the fold). For someone on a slow connection that can mean seeing a blank screen for seconds.
Side-note: The main reason why the browser block rendering until it has the styles is to avoid FUOC.
How to fix render blocking CSS?
Inline critical styles
Critical-path styles are the styles that are required to render correctly everything that's above the fold.
You should inline these styles to avoid additional HTTP requests blocking initial rendering. You'll find that there's a collection of tools to help with this.
<head> ... <style>critical CSS rules here</style> ... </head>
Some additional tips:
- You should consider figuring out what above-the-fold means for your users based on web analytics.
- Also make sure you don't use
@importstatements in critical CSS as that'll also trigger additional HTTP requests.
- Be sure not to inline too much CSS as that'll also slow down your initial render.
- Read some more explanation/tips from Google and Varvy.
Load non-critical CSS asynchronously
Inlining your critical CSS is not enough as the browser will still block rendering as soon as it encounters your non-critical CSS referenced using a
Luckily there's a new browser feature called Preload (aka
rel=preload) that allows us to start fetching our CSS but prevent it from blocking. At the moment it's only supported on Chrome but it can be polyfilled on other browsers.
See recommended usage in the polyfill docs. Your code for this will look something like this:
<head> ... <link rel="preload" href="/non-critical.css" as="style" onload="this.rel='stylesheet'"> <script>inlcude loadCSS polyfill here</script> ... </head>
Tip: The linked polyfill is not in any module format but with Webpack you can just use the script-loader to make sure it runs properly.
rel=preload for styles)