Editor’s note: This article was updated on 28 January 2022 to include information about the release of Google’s Core Web Vitals.
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:
@import
rulemedia
attribute for conditional CSSdefer
and async
attributes to eliminate render-blocking JavaScriptIf 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:
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).
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.
As a rule of thumb, the browser treats everything it finds in the <head>
section of an HTML page as render blocking. This includes:
<head>
sectionImages, 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.
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:
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:
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.
@import
ruleYou can add CSS to a page using either:
<link rel="stylesheet">
tag that you need to add to your HTML file@import
rule that you need to add to your CSS fileEven 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>
media
attribute for conditional CSSBy 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.
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:
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.
defer
and async
attributes to eliminate render blocking JavaScriptSimilar 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.
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.
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.
Popular content management systems such as WordPress also have cleanup plugins that let you remove your unused CSS and JavaScript automatically.
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.
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.
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.
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.
In this article, we discussed nine strategies to eliminate render blocking resources. To summarize:
media
attributesdefer
and async
attributes to eliminate render-blocking JavaScriptTo 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.”
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 see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
ElectricSQL is a cool piece of software with immense potential. It gives developers the ability to build a true local-first application.
Leptos is an amazing Rust web frontend framework that makes it easier to build scalable, performant apps with beautiful, declarative UIs.
Learn more about the 5 best JavaScript libraries for dealing with multidimensional arrays, such as ndarray, math.js, and NumJs.
We spoke with Dom about his approach to balancing innovation with handling tech debt and to learn how he stays current with technology.
16 Replies to "9 tricks to eliminate render blocking resources"
I had recently created a website on wordpress eBetterBooks and was having this issue and I referred to your blog and was able to fix it. Thanks a lot!
Great content! It refreshed & clarified some of my doubts. Thanks!
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
What if I want to use a wordpress optimization plugin?
Seriously. Very useful
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
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
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.
Simple and easy way to avoid rendering issues – add ‘prerender’ in your html, like this (but not to your main css page):
Also don’t forget to put your scripts at the bottom of the html body and add ‘defer’:
http://js/jquery.min.js
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…
İ have a website named oyun delisi and my css lowering my speed page. itried to defer but it can not suitable.
Thank you, it really helped me.
Thank you so much for the awesome post, Anna. Very useful to my website and got faster than before.
Very useful for my website. Thank you
Superb! I did these tricks and got awesome SPI results for my website. Thanks
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?