This article explains the performance impact of render blocking resources and what you can do to solve these issues.
What are render blocking resources?
Browsers load a large number of resources when loading a web page, for example CSS files or images. If a resource is render blocking then the browser doesn't start showing page content until that resource has finished loading.
The screenshot below shows a rendering filmstrip and request waterfall for a website. While the request for the HTML document finishes after 600 milliseconds, the browser still shows a blank page at that point.
The browser only starts rendering the page once three additional resources have finished loading:
- A CSS file (
- Another CSS file (
You can test your own website using the DebugBear speed test.
How do render blocking resources impact site speed metrics?
How much a render blocking resource impacts page speed depends on a few factors:
- How large is the resources being downloaded
- Is a new server connection required to load the resource
- Is there a chain of render blocking resources (see below for more on this)
Impact on Core Web Vitals and SEO
As LCP is a Core Web Vitals metric, having too many render blocking resources can hurt your Google rankings.
However, if you delay loading resources until later that could also cause layout shift when the resource is finally loaded.
What are render-blocking request chains?
A render blocking request chain happens when a render blocking resource triggers a request for another render blocking resource.
In this example the render blocking CSS file is loaded after 400 milliseconds. But that CSS file uses
@import to reference another CSS file. This file also needs to be downloaded before the page renders after 700 milliseconds.
The longer these chains are the bigger the performance impact will be.
Notably, the second CSS also requires a new server connection to be established to
fonts.googleapis.com. Because of this the request will take longer than if another resource from
discord.com had been loaded.
What does parser blocking mean?
Scripts and stylesheets referenced in the head always block all rendering (at least if they are loaded synchronously). These are called initial render blocking.
But what about resources referenced in the body? Chrome marks those as
in_body_parser_blocking. Whether they block render depends on where in the body they appear.
If they are placed at the end of the body tag then parser blocking scripts don't block rendering. But if a parser blocking script appears at the top of the body tag the script will block rendering.
Parser blocking resources are also called "subsequent render blocking".
How to identify render-blocking resources
async attribute is used, as we'll see later on in this article).
Let's take a look at how different tools report render-blocking requests.
DebugBear and WebPageTest
We've already seen how DebugBear highlights render blocking requests. We use the data that Chrome provides in the
ResourceSendRequest trace event.
WebPageTest uses the same data and highlights render blocking requests using an orange badge.
The Lighthouse report shown on PageSpeed Insights also contains an "Eliminate render-blocking resources" audit.
However, this doesn't use the Chrome data and can sometimes miss render blocking files. For example, in the Discord example the Google Fonts CSS is incorrectly not shown as render blocking.
How to eliminate render blocking resources
What you need to do to remove a render blocking request depends on the type of resource that's being loaded.
You might need to change script tags to load asynchronously or inline critical CSS.
Render blocking script tags
For example, in this case the browser will first run
chat.js and then
h1 tag is only shown after running the scripts.
However, many scripts don't need to be render blocking and can be run asynchronously. You can achieve that using the
<script src="chat.js" async></script>
<script src="analytics.js" async></script>
h1 will no longer be blocked.
analytics.js finishes loading before
analytics.js will run without first waiting for the chat widget code. If you want to maintain the order of execution you can use the
This waterfall chart demonstrates the impact that
defer have on page load behavior.
Render blocking CSS
Reducing render blocking stylesheets is harder than reducing render blocking scripts, as a page will often look very different if stylesheets are missing. If you made an important stylesheet load asynchronously you'd get a flash of unstyled content (FOUC).
While loading key CSS files asynchronously is not an option, loading stylesheets for third party code can be more viable, for example if you have a third party widget that's only used further down on the page. In that case updating the styling later on is acceptable. Another candidate for asynchronous CSS loading would be a stylesheet that only loads font references but does not affect the page layout.
Let's say you have this stylesheet in your HTML:
<link rel="stylesheet" href="widget.css">
widget.css will block rendering. To load the stylesheet asynchronously you can initially set the
media attribute to
all to apply the styles to the page.
<link rel="stylesheet" href="widget.css" media="print" onload="this.media='all'">
Inlining critical CSS
Another way to remove render blocking CSS files is to embed the styles directly in the HTML document. This will increase the size of the HTML, but it can be a great solution for small CSS files under 10 KB.
Here's an example website where render blocking CSS is inlined into the page HTML. The page renders immediately after the document is loaded.
When we look at the page HTML we see a large inline
The downside of this approach is that the CSS has to be downloaded again with every HTML request, while a separate CSS file could have been in a cache. How bad this is depends on the amount of CSS being inlined.
How to reduce the performance impact of render blocking resources
Often not all render blocking resources can be eliminated. But you can still reduce the impact they have on performance.
Reduce file size
Downloading large files takes longer than downloading small files. Therefore, reducing the size of critical requests can speed up your website.
There are a few ways to reduce file size:
- using better content encoding, e.g. switching from gzip to brotli
- making sure only the most important content is included in blocking files, and additional content can then be loaded later on
Reduce resource competition
Network connections can only provide a limited amount of bandwidth, so check if other resources are competing with the render blocking requests.
Here's an example of what resource competition looks like in a waterfall chart. The
Reuse server connections
Connecting to a new server requires the browser to do a DNS lookup, establish a TCP connection, and enable a secure SSL connection. Each of these steps requires at least one round trip on a network. The browser can only start making the HTTP request once the connection is established.
For example, the Substack website is located on
substack.com but then loads additional render blocking resources from
In contrast, the gov.uk website loads all resources from
gov.uk and can therefore reuse the existing server connection.
Reduce request chaining
Render blocking request chains happen when a render blocking resource starts loading another render blocking resource.
We saw this briefly earlier on in this article when we looked at how to identify render blocking files. The Discord homepage used
@import to load a stylesheet from Google Fonts.
The browser first needs to load the Discord stylesheet to discover the Google Fonts file. We can use a preload resource hint to help the browser discover the resource sooner.
<link rel="preload" as="style" href="https://fonts.googleapis.com/css?family=Press+Start+2P">
Adding this hint in the document HTML means the browser will start loading it without first waiting for the Discord CSS file.
This waterfall shows the page requests without the preload and then with the preload. After adding the preload the start time of the fonts CSS requests shifts to the left.
@import does for CSS. If a render blocking script synchronously creates a new script element with
This waterfall shows an example where
script.js synchronously adds
jquery-3.6.0.js to the page and thus delays rendering.
Again, this could be fixed by using a preload hint. Putting the script tag directly into the document HTML instead of using
document.write would also address the issue.
Is the HTML document request render blocking?
The HTML document is at least partially render blocking, as the browser can't show the page without knowing what its contents are. To find that out the web server needs to start sending the HTML code to the client.
Therefore a slow Time to First Byte (server response time) will make your website render more slowly.
However, browsers use streaming parsers that start processing the HTML as soon as it comes in, rather than waiting until the full document has been downloaded. Therefore, pages can start rendering before the document has finished loading.
This example shows that the other resources referenced in the HTML document start downloading before the HTML request has completed.
Are web fonts render blocking?
Web fonts don't block rendering of the page, but they can block rendering of the text itself. How text renders before fonts are loaded is specified by the
font-display CSS property.
Waiting for web fonts can slow down your First Contentful Paint if no other content is rendered on the page. If your text is still hidden but an image has rendered somewhere on the page then web fonts won't make your FCP worse.
The Largest Contentful Paint will be impacted if the LCP element is a text node using a web font.
Are images render blocking?
Images are not render blocking. They can delay metrics like the Largest Contentful Paint, but the rest of the page will still render fine even if the browser is still downloading an image file.
Why isn't my page rendering after all render blocking resources have loaded?
Sometimes the request waterfall suggests that all render blocking requests have finished, but the filmstrip will still show a blank page. This can have a few reasons.
Is content being hidden with CSS?
Some A/B testing tools set the body opacity to 0 to avoid flicker, delaying when the page renders.
Single page apps
Parser blocking resources
As mentioned above, synchronous scripts or stylesheets in the body block all rendering of content below that tag. This isn't a problem if the tags are placed at the end of the body tag, but if they appear before important content then rendering will be delayed.
Monitoring rendering milestones
DebugBear can help you detect render blocking resources, optimize your site speed, and monitor Core Web Vitals and other performance metrics over time.
Once you've reviewed your metrics you can investigate test results in depth. Start a free trial today.