As it is, JavaScript makes rendering a challenge. If and when search engines have a problem rendering your content, it will show up a blank page. And to add, if the browser encounters render-blocking resources, it will make this state (blank page) last longer unless you change that.
In this article, we’re going to explore what render-blocking resources are, why you should care about them, and how we can eliminate or handle them effectively to improve the UX and rankings of our site.
What are Render-Blocking Resources?
Render-blocking resources are critical files, usually CSS and JavaScript, that put the rendering process on pause while the client (e.g., a browser or a search bot) downloads, evaluates, and executes them. Until these render-blocking resources are dealt with, the client won’t finish rendering the page. But why are these resources render-blocking? This makes more sense if you understand the rendering process.
What Makes a Resource Render-Blocking?
When you enter a URL in your browser’s address bar, the browser sends a request to that address– basically asking the server for the files needed to construct the page on your screen.
However, websites are just a bunch of files filled with code, which isn’t very helpful for you who just want to access the information on the page.
Using the files sent by the server, the browser can generate a visual representation (rendering) of the HTML, CSS, and JavaScript, providing you with what you actually see on your screen.
The problem begins when you consider the role of CSS and JavaScript files. Although the information you want is – more often than not – in the HTML file, CSS tells the browser how to show these elements, and JavaScript provides functionalities that can also alter the appearance of or information on the page.
Because these two files significantly impact the page’s finished (rendered) version, the browser will stop parsing the HTML as soon as it finds a stylesheet or JS file to fetch and execute them.
Source: flaviocopes.com
In other words, they become render-blocking because they are needed to render the page properly, so the browser stops everything it’s doing before those files are taken care of.
How Render-Blocking Resources Affect Your Core Web Vitals
Core web vitals (CWVs) are metrics used by Google to measure your site’s performance and are part of the page experience signals. Most importantly, Google is now only using CWVs to measure site speed.
PageSpeed is also a confirmed ranking factor.
Although some of the tactics we’ll be talking about today can help you improve your overall PageSpeed, we’ll focus on the largest contentful paint (LCP) metric, which is the one getting affected by render-blocking resources. This metric measures the time it takes for the browser to render the largest content on the screen (a.k.a. Above-the-fold content). It’s important because it gives a quick signal to the end user that the page is functioning.
Just imagine this:
You do a search on Google and click on a website, and for several seconds, the page is entirely blank. What’s your first thought? For us: “This page is broken!”. In fact, several studies have shown that 53% of people will bounce off your site after 3 seconds. And that’s what render-blocking resources cause.
If the files are big enough, too many requests are being made, or the code is not optimized, render-blocking resources can delay LCP for several seconds.
Now that we know what’s happening, let’s take care of this issue together!
Handling Render-Blocking Resources for SPAs and JS-Heavy Enterprise Sites
Single-page applications (SPAs) use JavaScript frameworks (e.g., Angular, React, or Vue.js) to load information and dynamically update the page’s content.
Instead of loading separate HTML pages for each interaction or navigation, a SPA dynamically updates the content within the existing page (HTML template) by manipulating the DOM (Document Object Model) using JavaScript without requiring a full page reload.
This provides a smoother and more interactive user experience. Similar to a desktop application.
However, this means that before JavaScript is executed, there’s nothing to show on your page, not even above-the-fold content.
Something similar happens to JS-heavy sites that rely on JavaScript to, for example, update a list of products, show new content, or populate tables of data in real time.
So, how can we handle render-blocking resources without breaking our site?
Finding Render-Blocking Resources
The first thing you’ll need to do is identify the resources that are blocking your site’s rendering. Although there are several ways you can do this, let’s focus on the easiest and fastest one: WebPageTest.
Navigate to the tool and paste the URL you want to analyze in the bar.
The test will take a couple of minutes.
Once it’s ready, it’ll provide all sorts of information, including core web vitals scores.
Nevertheless, what you actually care about – in our current case – is the waterfall image. Which shows the rendering process and the resources that needed to be fetched.
In this waterful, the thin green line represents the “start rendering” point. Any files fetched before the rendering start line (which in the example above starts at 6 seconds) are potential render-blocking resources.
If you want a simpler report to get you started, you can also use PageSpeed Insights, which has a report on render-blocking resources, but it doesn’t show as much information as WebPageTest, so keep that in mind.
Identify Critical and Non-Critical Resources
Once you have the list of resources, it’s time to start testing them.
You want to know which resources are core to your page’s rendering and which add extra functionality but can be dealt with later in the rendering path.
Here’s what we mean. If you go to the DevTools network tab and refresh the page, it’ll record all network activities, and you can see what files are being fetched and when. From there, you can start blocking individual files and see what happens.
For example, if we refresh duolingo.com, here’s how things look:
But, if we block the request to “d35aaqx5ub95lt.cloudfront.net/js/manifest-b424c197.js”, nothing renders:
The idea of this exercise is to find critical resources (those required to render the page’s above-the-fold content or main content of the page) which are by nature render-blocking, so we can handle them appropriately.
1. Defer non-critical JavaScript
Adding the defer attribute to a script tag tells the browser to download the JavaScript file in parallel (or to fetch it asynchronously) of parsing the HTML but wait until the HTML is completely ready before executing.
Source: flaviocopes.com
Of course, you don’t want to defer the critical JavaScript. To avoid this, one strategy you can use is code splitting to create and deliver JS in bundles when it’s needed.
That way, you can let the above-the-fold JS render as usual – which is just a fraction of the JS – and defer the non-critical JavaScript, including 3rd-party scripts like analytics.
Single-page applications can do the same with components that are not used on the first painting of the page.
2. Defer non-critical CSS
CSS stylesheets can also be deferred to speed up your website’s LCP.
Of course, just like with JavaScript, you should only defer non-critical CSS. Otherwise, you’ll be harming your site in other ways:
- Without CSS, even though the page will definitely render faster, it will look like a messy combination of text and images without any layout.
- Once CSS is downloaded, the page will start to flicker and organize all the information, including changing the font, moving things around, etc.
This last point is not only terrible for the user experience, but it’s also bad for core web vitals.
Cumulative layout shift (CLS) measures the time it takes for the page to stabilize. Deferring necessary CSS will make your CLS score lower.
However, you can defer those CSS rules that don’t affect your above-the-fold content (improving LCP) and keep render-blocking the CSS rules needed to stabilize your site during the rendering process.
See also: How to Pass Core Web Vitals
3. Inline critical CSS
Once you have split your CSS and deferred everything that’s not critical, you can also inline above-the-fold CSS to improve your LCP scores even more.
<!DOCTYPE html> <html> <head> <title>Inline CSS Example</title> <style> /* Inline CSS styles */body { background-color: #f1f1f1;font-family: Arial, sans-serif; } h1 {color: #333; } p {font-size: 16px;color: #666; } </style> </head> <body> <h1>Welcome to My SPA</h1> <p>This is an example of inline CSS in a single-page application.</p> </body> </html> |
This way, you reduce the number of requests needed to render the largest contentful paint.
If you’re unsure what your critical CSS is, use a tool like Critical, which “extracts & inlines critical-path (above-the-fold) CSS from HTML.” Reducing manual work and helping reduce the number of render-blocking resources clients need to deal with.
4. Minify CSS and JS Files
As we’ve said, CSS and JS files are sometimes required to render your page correctly. Still, that doesn’t mean that we should just let them be.
Downloading your files take time, but smaller files take less time. When you minify your files, you are “removing white spaces, deleting comments, using shorter names, and basically stripping out any part of (your) code unnecessary for our machines to run it.”
Note: You could use CSS Minifier and JavaScript Minifier for this.
Minifying and compressing your files will reduce their size considerably, reducing render-blocking time and speeding up your page’s rendering process.
5. Remove unused CSS and JS files
There’s nothing worse than resources that block your rendering and then go unused. These resources waste time and hurt your site’s performance without adding any value to the user’s experience.
To identify unused CSS, you can use a tool like PurgeCSS. It has guides for all major JavaScript frameworks. Here’s how the PurgeCSS team describes the tool:
“PurgeCSS analyzes your content and your CSS files. Then it matches the selectors used in your files with the ones in your content files. It removes unused selectors from your CSS, resulting in smaller CSS files.”
Note: It will be very handy if you use any CSS framework like TailwindCSS, Bootstrap, MaterializeCSS, etc.
In the case of JavaScript, the process is very much manual and should be done by someone with experience, or you risk breaking your site.
To identify files you should start optimizing, go to sources > page > coverage in DevTools and refresh the page to begin recording.
In the report, you can see the type and total size of every file downloaded by your browser, and then, it will provide the size of unused code downloaded – in the visualization, it is represented by the red bar.
For example, from the main JS file we disabled earlier, 54% went unused when rendering the page.
Reducing this number – or at least splitting it to defer the unused code – will make a significant improvement.
6. Preload or load locally external fonts
External fonts called from the head section – or even within a stylesheet – are also considered render-blocking resources and can take a toll on your site’s performance. This mainly happens because external fonts are bloated with several variants you won’t use.
Similar to other resources, we can tell the browser to download this asset asynchronously using the <link rel=”preload”> “which will trigger a request for the WebFont early in the critical rendering path” without pausing the rendering of other elements.
Here’s a complete guide on optimizing WebFonts rendering and avoiding periods of invisible fonts.
Another solution – and the one we think it’s the best – is to load your fonts locally:
- Obtain the font files – You need to have the font files in the appropriate format (preferably .woff, .woff2) for web usage.
- Include the font files in your project – Place the font files in a directory within your project’s file structure. It’s common to create a “fonts” directory at the root level of your project or within your assets folder.
- Define the @font-face rule – Open your CSS file or style block and use the @font-face rule to define the custom font. Specify the font-family name, font file paths, and other relevant descriptors. Here’s an example:
@font-face {font-family: ‘CustomFont’;src: url(‘fonts/CustomFont-Regular.ttf’) format(‘truetype’);font-weight: normal;font-style: normal;} |
Note: Make sure to adjust the url() path based on the location of your font files within the project.
- Apply the custom font – Once you’ve defined the @font-face rule, you can apply the custom font to specific elements in your CSS code. Use the font-family property and set it to the name you specified in the @font-face rule.
body {font-family: ‘CustomFont’, Arial, sans-serif;} |
7. Generate a snapshot for search engines with Prerender
After implementing the previous strategies, you’ll see a considerable improvement in performance and LCP scores, and your customers will thank you for it.
However, there’s a big difference between how your end user’s browser and Google handle JavaScript.
How Google Renders Your Page
When your customer navigates to your site, her device has an entire CPU to use in the rendering process, and if it’s connected to a high-speed wifi connection, it can handle rendering even faster.
On the other hand, when Googlebot navigates to your site, it first needs to crawl the page to find all the resources required to render your page. If it’s just HTML and CSS, then there’s no problem. Googlebot can easily render your page and see your content.
In this scenario, everything we’ve done to improve your page’s CSS will return a positive ROI.
But if it finds a JavaScript file, the crawler will send all resources to the Renderer to process the JS and start the rendering process.
The problem is that Google is more than just crawling your site. It’s crawling and trying to render millions of websites monthly, so resources are scarce. In most cases, it can take 9x times longer for Google to crawl a JS site.
In fact, Google has suggested for years to use other rendering techniques to take the rendering step off their shoulders and ensure its crawler can access your content thoroughly.
In other words, there’s a cap on how well and fast Google can render your JavaScript content, no matter how well-optimized it is—putting a cap also on your core web vitals scores.
Solving JavaScript SEO with Prerender
In simple terms, Prerender is a tool designed to help overcome the limitations of search engines so you can focus on user experience instead of optimizations for search bots.
After installing Prerender’s middleware, you can submit a sitemap through your dashboard, and Prerender will crawl your pages.
For each page, it’ll generate a fully rendered, stable, and functional version of your page and cache it as a snapshot. Then, when a search bot (or any other bot you specified) request your page, Prerender will identify the bot and send the snapshot instead.
This snapshot is wholly rendered, including 3rd-party scripts, and it’s delivered in 0.03 seconds on average – pushing your CWVs and server response scores to near perfect.
Using Prerender will save you time and money by reducing the hours of work required to implement other solutions like hydration, which won’t return the same results as Prerender.
Prerender will help you fix render-blocking resource issues from their root and improve your site’s indexation rate and speed.
Wrapping Up
In the end, render-blocking resources are necessary files and code to render your pages properly.
Your objective is to control how and when these resources are dealt with to avoid putting above-the-fold content on pause (LCP) without hurting other UX metrics like first input delay (FID) or cumulative layout shift (CLS).
Before doing any drastic change – like deleting a piece of code or referring an entire JS file – make sure to test your site’s behavior with them disabled.
If you’re working on a SPA or an enterprise site, the best first step is installing Prerender. It takes just a couple of hours, and you can test it for free for the first 1,000 renders.
This will allow you to start competing in search results and see your SEO campaign in action while your team optimizes your critical rendering path to improve user experience and conversions.
Want to learn more about improving site performance? Check out these guides: