Wowzers, what a last few weeks. Last Tuesday morning (very, very early my time) I did my first online speaking engagement. It was at the Toronto Web Perf. Meetup, where the topic of the day was Web Sustainability. I spoke alongside Michelle Barker, and Jon Arne Sæterås. You can catch an unedited version of the event on YouTube - there’ll be more polished versions published on the same channel a bit later. Last night I also gave my first ever web performance workshop for a few folks from Taiwan Code Camp. I’m hopeful it can be the first of many.
When looking to optimise for paint metrics (First and Largest Contentful Paint for example), we’re almost certainly going to encounter render-blocking resources. In this post I’ll cover what they are, and some general tips on how to mitigate their impact on page performance.
What is a render-blocking resource?
The name says it all, to be honest. Render-blocking resources are like a roadblock for the browser as it goes about painting web page content to the screen. When encountering render-blocking resources, the browser waits until the code has been completely parsed and executed before it can continue rendering content in the viewport.
Common render-blocking resources
HEAD of a page. This includes inline code (found in
<style> tags) as well as linked resources (using the
<link> tag). Third-party requests and tag managers can also be a source of render-blocking requests.
CSS is always render-blocking
Regardless of what it’s doing at the time, the moment a browser encounters a CSS resource it will stop to download and parse the CSS. Once that’s out the way the browser will continue working on rendering content on the screen.
CSS can be loaded asynchronously to avoid render-blocking though if not carefully managed can result in unstyled content being shown before the stylesheet has been parsed.
When the browser finds a synchronous script on the page it will pause and fetch the file (if it’s called via a
<link> tag), then parse and finally execute the code.
<!-- CSS will download and parse first --> <link rel="stylesheet" href="/css/my-styles.css" /> <script src="/js/important-file.js"></script> <!-- JS will download, parse and execute first --> <script src="/js/important-file.js"></script> <link rel="stylesheet" href="/css/my-styles.css" /> <!-- JS will start downloading in parallel with the CSS file --> <script async src="/js/important-file.js"></script> <link rel="stylesheet" href="/css/my-styles.css" />
How can you find render-blocking resources?
If you’ve tested a page with Google’s PageSpeed Insights tool, then you’ll be able to identify any render-blockng resources in the Opportunities section of the test results.
The WebPageTest waterfall chart surfaces render-blocking resources, and marks the request row with an orange circle containing a white cross. You can see that in rows 2 and 4 of the truncated waterfall chart below.
Reducing the impact of render-blocking resources
Reduce the size of CSS
Since CSS will always be render blocking, the best way to reduce its impact on performance is to reduce the amount of CSS you’re using.
- Are you able to inline critical CSS on a page, and load the rest later?
- Avoid using
@importstatements in your CSS.
- Can you self-host Google Fonts? This eliminates the outbound request for the font stylesheet.
- If you’re using an icon font, try replacing that with SVGs.
Reduce the size of JS
- Can you use code-splitting and tree-shaking in your build process?
- Can you use the import on interaction pattern?
- Defer any code you don’t need right away, and load the rest asynchronously.
Execute code off the main thread
Move A/B testing to the server
Client-side A/B testing is a recipe for poor rendering performance. This is because the script to run the A/B test must first download, before it is then parsed an executed. As a result, content is hidden from the user until code execution is completed.
Moving A/B testing to the server prevents this entirely. If you are server-side rendering you site then you can perform all the heavy lifting before sending the page back to the browser. Another approach is to use edge compute like Cloudflare Workers to perform the A/B tests.
Use a web worker
Third-party code like analytics, ads, and other tracking scripts probably aren’t critical to rendering content on your page. Sure, they might be important for your business, but you can defer their loading until after the rest of the page’s content has been loaded.
Alternately, you can move the execution of these scripts off the main thread using web workers This is an area I’ve got to explore more, so there could be a post about it later in the year. If you want to learn more, Surma has a great post & talk about the topic. There are also tools like Partytown & Cloudflare’s Zaraz which are worth checking out.
Reducing The Web’s Carbon Footprint: Optimizing Social Media Embeds
An article from fellow Toronto Web Perf. presenter Michelle Barker looking into the weight of social media embeds from an environmental stand point. It includes some really handy, practical tips to reduce their impact.
The next issue of Optimised will be in your inbox on March 4th. The website has an archive of all previous emails. It's a good place to recap on anything we've covered, and also handy to share with friends or colleagues.
Keep well, stay safe.