Anna Monus Anna is a technical writer who covers frontend frameworks, web standards, accessibility, WordPress development, UX design, and more. Head to her personal blog Annalytic for more content.

9 tricks to eliminate render blocking resources

11 min read 3359

5 Tricks to Eliminate Render Blocking Resources

Editor’s note: This article was updated on 28 January 2022 to include information about the release of Google’s Core Web Vitals.

What are render blocking resources?

Render blocking resources are static files, such as fonts, HTML, CSS, and JavaScript files, that are vital to the process of rendering a web page. When the browser encounters a render blocking resource, it stops downloading the rest of the resources until these critical files are processed. In the meantime, the entire rendering process is put on hold.

On the other hand, non-render blocking resources don’t postpone the rendering of the page. The browser can safely download them in the background after the initial page render.

However, not all resources that the browser deems render blocking are essential for the first paint; it all depends on the individual characteristics of the page. There are best practices you can use to turn these noncritical render blocking resources into non-render blocking ones. Besides, you can also decrease the number and/or size of render blocking resources that are still critical and can’t be eliminated.

In this article, I will review nine tips and tricks to eliminate render blocking resources. They are:

    1. Identify your render blocking resources
    2. Don’t add CSS with the @import rule
    3. Use the media attribute for conditional CSS
    4. Defer non-critical CSS
    5. Use the defer and async attributes to eliminate render-blocking JavaScript
    6. Find and remove unused CSS and JavaScript
    7. Split code into smaller bundles
    8. Minify CSS and JavaScript files
    9. Load custom fonts locally

Why eliminate render blocking resources?

If you reduce the number of render blocking resources, you can shorten the critical rendering path and reduce page load times, thus improving the user experience and search engine optimization.

There are three ways to reduce the number and impact of render blocking resources:

  1. Make them non-render blocking resources by deferring their download
  2. Decrease the total number of render blocking resources using techniques such as bundling (this also means fewer HTTP requests)
  3. Reduce the size of a resource via minification so that the page has fewer bytes to load

Render blocking resources and Core Web Vitals

Even though the elimination of render blocking resources has always been an important performance optimization technique, the introduction of Core Web Vitals, Google’s new performance metrics, has made it even more important.

As Core Web Vitals are included in Google’s search algorithm, you simply can’t ignore them if you want your site to rank high in Google. Render blocking resources can negatively impact one of the three Core Web Vitals: the Largest Contentful Paint (LCP).

Chart of Google Core Web Vitals
Source: https://web.dev/vitals/#core-web-vitals

LCP measures the rendering time of the largest image or text block that’s visible in the user’s viewport. If your critical rendering path is too long (you have too many render blocking resources, or the files are too large), the largest content element will take longer to load. So, for a better LCP score, it’s recommended to keep the number and weight of your render blocking resources in check.

Types of render blocking resources

As a rule of thumb, the browser treats everything it finds in the <head> section of an HTML page as render blocking. This includes:

  • CSS stylesheets
  • JavaScript files added in the <head> section
  • Fonts added from either CDN or a local server
  • HTML imports (even though HTML imports are now obsolete, you might still encounter them on legacy pages)

Images, media files, and <script> tags placed at the bottom of the <body> section are treated as non-render blocking resources.

Now let’s zoom in on nine strategies to eliminate or reduce the number and impact of render blocking resources.

1. Identify your render blocking resources

Whether you have an existing website or it’s still in the development phase, the first thing to do is find your render blocking resources so that you can decide how to handle them. Luckily, these days there are many free performance metrics tools you can use for this purpose.

The most notable ones are Lighthouse, which is now part of Chrome DevTools, PageSpeed Insights, and GTmetrix. Both PageSpeed Insights and GTmetrix are free web apps that use the Lighthouse library to measure page speed, Core Web Vitals, and other performance metrics.

However, in Lighthouse, you’ll only see the Eliminate render blocking resources flag in the Opportunities section of your performance report if your render blocking resources cause performance issues on your site.

For instance, here’s Lighthouse’s warning for BBC’s homepage:

Core web vitals on BBC homepage

If you want to get feedback about your render blocking resources anyway, use one of the aforementioned web apps. In addition to identifying your render blocking resources, they also provide you with useful tips on how to eliminate them.

For example, here’s the relevant part of GTmetrix’s report for LogRocket’s blog page. You can see that the Eliminate render blocking resources recommendation has low priority, but the files that “may be contributing to render blocking” are still listed:

Core web vitals on the LogRocket blog site

How you’ll be moving on from here depends on your goals. If you received a warning about render blocking resources, you should try and eliminate them. If you didn’t, you can still apply some of the following techniques, as they can still improve your page load times and Core Web Vitals scores.

2. Don’t add CSS with the @import rule

You can add CSS to a page using either:

  • The <link rel="stylesheet"> tag that you need to add to your HTML file
  • The @import rule that you need to add to your CSS file

Even though the @import rule keeps your HTML file cleaner and allows you to keep all your CSS dependencies in the same place, it’s not the best choice performance-wise. The @import rule lets you import CSS from other stylesheets, but this causes the browser to process your CSS file more slowly because it also has to download the imported files. Until this takes place, the rendering process will be blocked.

If you want to add more than one CSS file to your page, you can either use the <link> tag or concatenate the files using a minification and/or bundling tool.



You need to add the <link> element to the <head> section of the HTML page in the following way:

<head>
  <link href="style.css" rel="stylesheet">
</head>

3. Use the media attribute for conditional CSS

By default, the browser treats all CSS files as render blocking resources. However, if you add the media attribute to the <link> tag, you can indicate the presence of a conditional CSS file to the browser.

Conditional CSS only applies under certain conditions, such as below or above a given viewport size or on a print page. With the media attribute, you can define a specific media condition for a CSS file. You can use any value that you would use for a media query in a CSS file. For example:

<link href="print.css" rel="stylesheet" media="print">
<link href="large.css" rel="stylesheet" media="screen and (min-width: 1500px)">
<link href="mobile.css" rel="stylesheet" media="screen and (max-width: 600px)">

Even though these files are still downloaded on all devices, they become non-render blocking resources if the condition evaluates as false. However, they will still be render blocking if the condition evaluates as true.

For instance, the mobile.css stylesheet in the above example will be render blocking on mobile devices with a maximum viewport width of 600px and non-render blocking on viewports larger than 600px.

If you have an existing CSS file with one or more media queries, you can extract all @media rules and save them as separate files using this PostCSS plugin.

4. Defer non-critical CSS

All the CSS files that you place into the <head> section of your HTML page are automatically treated as render-blocking resources. However, you don’t need all of this code to render the critical part of your page: above-the-fold content. Splitting CSS into critical and non-critical parts is a performance optimization technique that has gained a lot of popularity since the introduction of Core Web Vitals, as it also improves LCP scores (i.e. the rendering time of the largest content element above the fold).

Luckily, you don’t have to find your critical-path CSS manually — even though it’s possible to do so. You can use online tools, such as the Critical Path CSS Generator or Addy Osmani’s Critical library, to extract the CSS rules that are related to your above-the-fold content.

Critical Path CSS Generator, for example, generates two downloadable CSS files: a “critical” and a “combined” one. You can either add the critical CSS file as an external resource to the <head> section or inline it using the <style> tag to also reduce the number of HTTP requests.

The combined CSS file includes all your CSS rules, and you need to move it down before the closing <body> tag so that it will become a non-render-blocking resource. You can read the instructions in detail below the generator, but here’s what your optimized code should look like:

Critical path CSS generator
Source: https://www.sitelocity.com/critical-path-css-generator

Optionally, you can also use JavaScript to dynamically load below-the-fold CSS after the browser finishes downloading the page. This technique is also detailed under the Critical Path CSS Generator (method number two) and will further improve your site’s performance. However, it won’t contribute to the elimination of render blocking resources as non-critical CSS has already been moved out of the <head> section.

5. Use the defer and async attributes to eliminate render blocking JavaScript

Similar to CSS, JavaScript files added to the <head> section of the document are also treated as render blocking resources by default.

You can remove them from the critical rendering path by placing the <script> tags right before the closing </body> tag instead of the <head> section. In this case, they only begin to download after the entire HTML has been downloaded. However, because the download of these scripts starts later, elements loaded by them, such as ads, animations, or dynamic functionalities, might load later than the rest of the frontend, especially if it’s a longer script. This can result in noticeable delays and lagging UIs on slower connections, which is bad for the user experience.

The defer and async attributes of the <script> tag offer a solution to this problem. Both are Boolean attributes which means that if you add them, they will fire without any further configuration. They also make scripts added to the <head> section of an HTML document non-render blocking, but in a different way; deferred scripts respect the document order while asynchronous scripts are independent of the DOM.

The defer attribute instructs the browser to download the script in the background so it won’t block the rendering of the page. The deferred script executes once the DOM is ready but before the DOMContentLoaded event fires.

<script src="script01.js" defer></script>
<script src="script02.js" defer></script>

Deferred scripts follow the document order, just like nondeferred, default scripts. For example, in the above example, script01.js will be executed first, irrespective of which script loads first. You can’t add defer to inline scripts; it only works with external scripts that specify the script’s location using the src attribute.


More great articles from LogRocket:


On the other hand, the async attribute informs the browser that a script is completely independent of the page. It will download in the background as a non-render blocking resource, just like deferred scripts. However, unlike deferred scripts, async scripts don’t follow the document order, so they will execute whenever they finish downloading — which can happen at any time.

For instance, in the below example, we can’t be sure which script will run first; it solely depends on which downloads faster (usually the smaller one). Remember, async scripts are independent of both the document and each other, so the document order won’t impact them in any way.

<script src="script03.js" async></script>
<script src="script04.js" async></script>

The defer attribute is recommended for scripts that need the DOM, but you want to begin to download them before the document loads, without making them a render blocking resource. You should also use defer rather than async if the document order is important — for instance, when consecutive scripts depend on each other.

The async attribute is recommended for independent third-party scripts, such as ads, trackers, and analytics scripts. For example, Google Analytics recommends adding the async attribute to support asynchronous loading in modern browsers.

6. Find and remove unused CSS and JavaScript

Apart from deferring non-critical CSS and JavaScript, it’s also recommended to check if you have any unused CSS or JavaScript on your site. You can do so with the help of code analysis tools such as PurgeCSS that checks your CSS code and removes any unused selectors from it, including the ones added by third-party libraries or frameworks such as Bootstrap.

Finding and removing unused JavaScript is a bit more tricky as you’ll need to analyze your code manually. You can perform a code analysis using Chrome DevTools’ Coverage tab (see the detailed instructions) that will highlight your unused code in red. Even though I only recommend this technique if you are good at JavaScript and know what you’re removing, it can also be a great way to locate third-party libraries that you barely use. If you find an asset like that, you can consider removing it from your site entirely.

Chrome devtools coverage tab
Source: https://developer.chrome.com/docs/devtools/coverage/

Popular content management systems such as WordPress also have cleanup plugins that let you remove your unused CSS and JavaScript automatically.

7. Split code into smaller bundles

You can use module bundlers such as Webpack, Rollup, and Parcel to split your code into smaller bundles and load each bundle on demand and even in parallel. Many of these smaller bundles are non-essential resources that can be safely lazy-loaded after the web page has been rendered. You might also have code that you only need to load if the user wants to use a specific part or feature of your page.

Even though it’s possible to perform code splitting and create smaller bundles manually, automation makes the process straightforward, safe, and fast. These days, most bundling tools come with zero-configuration code splitting functionality that works out of the box, but they also let you tweak the configuration manually if you want to.

8. Minify CSS and JavaScript

In addition to code splitting, you can also minify both render blocking and non-render blocking resources. Since minified files are lighter, initial page rendering will finish sooner. Plus, it will also take less time to download non-render blocking resources in the background.

There are numerous tools available to help you perform minification according to best practices, including Minify, CSS Minifier, Minify Code, and PostCSS. Build tools, such as Webpack, Parcel, and Rollup, also come with built-in minification functionalities that enable you to quickly reduce the weight of render blocking resources.

9. Load custom fonts locally

Because custom fonts are called from the <head> section of the document, they are also render blocking resources. For instance:

<link href="https://fonts.googleapis.com/css2?family=Lato&display=swap" rel="stylesheet">

You can reduce the impact of custom fonts on initial page rendering by adding them locally rather than pulling them from a content delivery network such as Google CDN. Font providers tend to add multiple @font-face rules, many of which you won’t need.

For example, Google Fonts adds @font-face rules for all the character sets a typeface comes with, such as Latin, Cyrillic, Chinese, Vietnamese, and others. Let’s say, for instance, that the online CSS file you add with the <link> tag includes @font-face rules for seven different character sets, but you only want to use one (e.g., Latin). However, Google Fonts doesn’t download the font files for all the character sets; they just add many redundant @font-face rules to the CSS file.

If you add fonts locally, you can also minify your font-related CSS and bundle it together with the rest of your CSS. You can use the Google Web Fonts Helper to generate local @font-face rules for Google Fonts quickly. For instance, this is what you need to add to include the Lato Regular font face:

/* lato-regular - latin */
@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: local('Lato Regular'), local('Lato-Regular'),
       url('../fonts/lato-v16-latin-regular.woff2') format('woff2'),
       url('../fonts/lato-v16-latin-regular.woff') format('woff');
}

Note that Google Web Fonts Helper doesn’t add the font-display: swap rule; I added it myself to the above declaration. This is a descriptor of the @font-face rule that lets you specify how the browser should display the font face on the page.

By using font-display with the swap value, you instruct the browser to immediately begin to use a system font and swap it with the custom font once it downloads (this rule is also added when you pull the font from Google’s CDN). This enables you to avoid invisible text on the page while the custom font is still loading.

When you load fonts locally, make sure you serve compressed font formats for modern browsers, such as WOFF and WOFF2. Remember that lighter files reduce the impact of render blocking resources too. In addition to generating the @font-face rules, Google Web Fonts Helper also lets you download a zipped file that contains all the font formats you need.

Why you shouldn’t load custom fonts asynchronously

Some articles about render blocking resources recommend using TypeKit’s Web Font Loader to load custom fonts asynchronously. It was a decent tool once upon a time, but it hasn’t been updated since 2017 and it has many unresolved issues. I wouldn’t recommend using it.

Although loading fonts asynchronously shortens the critical rendering path, you should always do it carefully. If fonts load later than the page content, the page can produce a common UX problem called flash of invisible text (FOIT).

There are various ways to handle FOIT, such as using third-party libraries or the aforementioned font-display: swap rule (see browser support for font-display, and note that using it with the swap value just turns FOIT into FOUT – flash of unstyled text – but doesn’t completely eliminate the issue). Still, you’ll want to spend time considering whether it’s really worth going the async route performance-wise. Think of the weight of extra scripts, potential issues, users with disabled JavaScript (you still need to add the static <link> element within <noscript> tags to support them), etc.

Summary

In this article, we discussed nine strategies to eliminate render blocking resources. To summarize:

  1. Identify your render blocking resources
  2. Don’t use CSS imports
  3. Load conditional CSS with media attributes
  4. Defer non-critical CSS
  5. Use the defer and async attributes to eliminate render-blocking JavaScript
  6. Find and remove unused CSS and JavaScript
  7. Split code into smaller bundles
  8. Minify CSS and JavaScript files
  9. Load custom fonts locally

To improve overall page load times, you can also use resource hints and the preload directive. They don’t eliminate render blocking resources per se, but you can use them to improve page load times. Render blocking resources won’t stop the fetching process of preloaded resources, and you can also preconnect to Google CDN to make web fonts load faster if you don’t want to load them locally.

For an in-depth guide to browser rendering, check out “How browser rendering works — behind the scenes.”

: Debug JavaScript errors more easily by understanding the context

Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.

LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

.
Anna Monus Anna is a technical writer who covers frontend frameworks, web standards, accessibility, WordPress development, UX design, and more. Head to her personal blog Annalytic for more content.

16 Replies to “9 tricks to eliminate render blocking resources”

    1. I used @ import for my website, djtconcept.ng, I compressed with gzip and minified it, and it reads 98% score on speed test, does it mean render blocking resources didn’t count. I will appreciate an answer

  1. Thank you very much, Anna Monus! This trick is very useful to my website and got faster than before. Btw do you have another tricks to eliminate render blocking resources for fontawesome css? Thanks again

  2. Thank you very much, Anna Monus! This trick is very useful to my website and got faster than before. Btw do you have another tricks to eliminate render blocking resources for fontawesome css? Thanks again

  3. Sage 50 Backup
    When you create a backup, an error occurs and the backup process stops. You may see one of the following messages on the screen of your computer: “Sage Backup Error” or “Backup failed.” A user may not be able to restore a backup created in Winzip if they are seeing the error that their backup failed. The mistake is that in C:\Documents and Setting instead of a folder for backup, create a folder called “Sage 50 Backup” and save your files inside it when you create your backup.

  4. So, after step 1, I now know what my render blocking resources are… it just tells me to eliminate them…. but how? That was supposed to be the whole point of this article. I still don’t know how to eliminate them. The article assumes you have this knowledge…

  5. To be clear, well over half of these fall directly into ‘wouldn’t it be nice if we could’, not ‘we can’:

    Identify your render blocking resources – wouldn’t be here if we hadn’t?

    Don’t add CSS with the @import rule – sure

    Use the media attribute for conditional CSS – uhhhh, so rewrite the entire bootstrap CSS core file?

    Defer non-critical CSS – how? not using wordpress or anything other framework that allows third party plugins?

    Use the defer and async attributes to eliminate render-blocking JavaScript – how? how would anyone defer or asynchronously load third party JS? 🤷‍♂️

    Find and remove unused CSS and JavaScript – LOL, that is a realistic and completely achievable task

    Split code into smaller bundles – again, LOL?

    Minify CSS and JavaScript files – you can’t do this to third party scripts. you can’t do this to third party CSS resources.

    Load custom fonts locally – i guess three out of your nine is better than none, right?

Leave a Reply