Despite significant changes to the organic search landscape throughout the year, the speed and efficiency of web pages have remained paramount.
Users continue to demand quick and seamless online interactions, with 83% of online users reporting that they expect websites to load in three seconds or less.
Google sets the bar even higher, requiring a Largest Contentful Paint (a metric used to measure a page’s loading performance) of less than 2.5 seconds to be considered “Good.”
The reality continues to fall below both Google’s and users’ expectations, with the average website taking 8.6 seconds to load on mobile devices.
On the bright side, that number has dropped 7 seconds since 2018, when it took the average page 15 seconds to load on mobile devices.
But page speed isn’t only about total page load time; it’s also about what users experience in those 3 (or 8.6) seconds. It’s essential to consider how efficiently pages are rendering.
This is accomplished by optimizing the critical rendering path to get to your first paint as quickly as possible.
Basically, you’re reducing the amount of time users spend looking at a blank white screen to display visual content ASAP (see 0.0s below).
Example of optimized vs. unoptimized rendering from Google (Image from Web.dev, August 2024)
What Is The Critical Rendering Path?
The critical rendering path refers to the series of steps a browser takes on its journey to render a page, by converting the HTML, CSS, and JavaScript to actual pixels on the screen.
Essentially, the browser needs to request, receive, and parse all HTML and CSS files (plus some additional work) before it will start to render any visual content.
Until the browser completes these steps, users will see a blank white page.
Steps for browser to render visual content. (Image created by author)
How Do I Optimize It?
The primary goal of optimizing the critical rendering path is to prioritize the resources needed to render meaningful, above-the-fold content.
To do this, we also must identify and deprioritize render-blocking resources – resources that are not necessary to load above-the-fold content and prevent the page from rendering as quickly as it could.
To improve the critical rendering path, start with an inventory of critical resources (any resource that blocks the initial rendering of the page) and look for opportunities to:
Reduce the number of critical resources by deferring render-blocking resources.
Shorten the critical path by prioritizing above-the-fold content and downloading all critical assets as early as possible.
Reduce the number of critical bytes by reducing the file size of the remaining critical resources.
There’s a whole process on how to do this, outlined in Google’s developer documentation (thank you, Ilya Grigorik), but I will be focusing on one heavy hitter in particular: Reducing render-blocking resources.
What Are Render-Blocking Resources?
Render-blocking resources are elements of a webpage that must be fully loaded and processed by the browser before it can start rendering the content on the screen. These resources typically include CSS (Cascading Style Sheets) and JavaScript files.
Render-Blocking CSS
CSS is inherently render-blocking.
The browser won’t start to render any page content until it is able to request, receive, and process all CSS styles.
This avoids the negative user experience that would occur if a browser attempted to render un-styled content.
A page rendered without CSS would be virtually unusable, and the majority (if not all) of content would need to be repainted.
Example page with and without CSS, (Image created by author)
Looking back to the page rendering process, the gray box represents the time it takes the browser to request and download all CSS resources so it can begin to construct the CCSOM tree (the DOM of CSS).
The time it takes the browser to accomplish this can vary greatly, depending on the number and size of CSS resources.
Steps for browser to render visual content. (Image created by author)
Recommendation:
“CSS is a render-blocking resource. Get it to the client as soon and as quickly as possible to optimize the time to first render.”
Render-Blocking JavaScript
Unlike CSS, the browser doesn’t need to download and parse all JavaScript resources to render the page, so it’s not technically* a “required” step (*most modern websites require JavaScript for their above-the-fold experience).
Yet, when the browser encounters JavaScript before the initial render of the page, the page rendering process is paused until after the JavaScript is executed (unless otherwise specified using the defer or async attributes – more on that later).
For example, adding a JavaScript alert function into the HTML blocks page rendering until the JavaScript code is finished executing (when I click “OK” in the screen recording below).
Example of render-blocking JavaScript. (Image created by author)
This is because JavaScript has the power to manipulate page (HTML) elements and their associated (CSS) styles.
Since the JavaScript could theoretically change the entire content on the page, the browser pauses HTML parsing to download and execute the JavaScript just in case.
How the browser handles JavaScript, (Image from Bits of Code, August 2024)
Recommendation:
“JavaScript can also block DOM construction and delay when the page is rendered. To deliver optimal performance … eliminate any unnecessary JavaScript from the critical rendering path.”
How Do Render Blocking Resources Impact Core Web Vitals?
Core Web Vitals (CWV) is a set of page experience metrics created by Google to more accurately measure a real user’s experience of a page’s loading performance, interactivity, and visual stability.
The current metrics used today are:
Largest Contentful Paint (LCP): Used to evaluate loading performance, LCP measures the time it takes for the largest visible content element (such as an image or block of text) to appear on the screen.
Interaction to Next Paint (INP): Used to evaluate responsiveness, INP measures the time from when a user interacts with the page (e.g., clicks a button or a link) to the time when the browser is able to respond to that interaction.
Cumulative Layout Shift (CLS): Used to evaluate visual stability, CLS measures the sum total of all unexpected layout shifts that occur during the entire lifespan of the page. A lower CLS score indicates that the page is stable and provides a better user experience.
Optimizing the critical rendering path will typically have the largest impact on Largest Contentful Paint (LCP) since it’s specifically focused on how long it takes for pixels to appear on the screen.
The critical rendering path affects LCP by determining how quickly the browser can render the most significant content elements. If the critical rendering path is optimized, the largest content element will load faster, resulting in a lower LCP time.
Read Google’s guide on how to optimize Largest Contentful Paint to learn more about how the critical rendering path impacts LCP.
Optimizing the critical rendering path and reducing render blocking resources can also benefit INP and CLS in the following ways:
Allow for quicker interactions. A streamlined critical rendering path helps reduce the time the browser spends on parsing and executing JavaScript, which can block user interactions. Ensuring scripts load efficiently can allow for quick response times to user interactions, improving INP.
Ensure resources are loaded in a predictable manner. Optimizing the critical rendering path helps ensure elements are loaded in a predictable and efficient manner. Effectively managing the order and timing of resource loading can prevent sudden layout shifts, improving CLS.
To get an idea of what pages would benefit the most from reducing render-blocking resources, view the Core Web Vitals report in Google Search Console. Focus the next steps of your analysis on pages where LCP is flagged as “Poor” or “Need Improvement.”
How To Identify Render-Blocking Resources
Before we can reduce render-blocking resources, we have to identify all the potential suspects.
Luckily, we have several tools at our disposal to quickly pinpoint exactly which resources are hindering optimal page rendering.
PageSpeed Insights & Lighthouse
PageSpeed Insights and Lighthouse offer a quick and easy way to identify render blocking resources.
Simply test a URL in either tool, navigate to “Eliminate render-blocking resources” under “Diagnostics,” and expand the content to see a list of first-party and third-party resources blocking the first paint of your page.
Both tools will flag two types of render-blocking resources:
JavaScript resources that are in <head> of the document and don’t have a <defer> or <async> attribute.
CSS resources that do not have a disabled attribute or a media attribute that matches the user’s device type.
Sample results from PageSpeed Insights test. (Screenshot by author, August 2024)
Tip: Use the PageSpeed Insights API in Screaming Frog to test multiple pages at once.
WebPageTest.org
If you want to see a visual of exactly how resources were loaded in and which ones may be blocking the initial page render, use WebPageTest.org.
To identify critical resources:
Run a test using webpagetest.org and click on the “waterfall” image.
Focus on all resources requested and downloaded before the green “Start Render” line.
Analyze your waterfall view; look for CSS or JavaScript files that are requested before the green “start render” line but are not critical for loading above-the-fold content.
Sample results from WebPageTest.org. (Screenshot by author, August 2024)
How To Test If A Resource Is Critical To Above-The-Fold Content
Depending on how nice you’ve been to the dev team lately, you may be able to stop here and just simply pass along a list of render-blocking resources for your development team to investigate.
However, if you’re looking to score some extra points, you can test removing the (potentially) render-blocking resources to see how above-the-fold content is affected.
For example, after completing the above tests I noticed some JavaScript requests to the Google Maps API that don’t appear to be critical.
Sample results from WebPageTest.org. (Screenshot bu author, August 2024)
To test within the browser how deferring these resources would affect above-the-fold content:
Open the page in a Chrome Incognito Window (best practice for page speed testing, as Chrome extensions can skew results, and I happen to be a collector of Chrome extensions).
Open Chrome DevTools (ctrl+shift+i) and navigate to the “Request blocking” tab in the Network panel.
Check the box next to “Enable request blocking” and click the plus sign.
Type a pattern to block the resource(s) you’ve identified, being as specific as possible (using * as a wildcard).
Click “Add” and refresh the page.
Example of request blocking using Chrome Developer Tools. (Image created by author, August 2024)
If above-the-fold content looks the same after refreshing the page – the resource you tested is likely a good candidate for tactics listed under “Methods to reduce render-blocking resources.”
If the above-the-fold content does not properly load, refer to the below methods to prioritize critical resources.
Methods To Reduce Render-Blocking
Once you have confirmed that a resource is not critical to rendering above-the-fold content, explore different methods for deferring resources and improving page rendering.
Method
Impact
Works with
JavaScript at the bottom of the HTML
Low
JS
Async or defer attribute
Medium
JS
Custom Solutions
High
JS/CSS
CSS media queries
Low-High
CSS
Place JavaScript At The Bottom Of The HTML
If you’ve ever taken a Web Design 101 course, this one may be familiar: Place links to CSS stylesheets at the top of the HTML <head> and place links to external scripts at the bottom of the HTML <body>.
To return to my example using a JavaScript alert function, the higher up the function is in the HTML, the sooner the browser will download and execute it.
When the JavaScript alert function is placed at the top of the HTML, page rendering is immediately blocked, and no visual content appears on the page.
Example of JavaScript placed at the top of the HTML, page rendering is immediately blocked by the alert function and no visual content renders.
When the JavaScript alert function is moved to the bottom of the HTML, some visual content appears on the page before page rendering is blocked.
Example of JavaScript placed at the bottom of the HTML, some visual content appears before page rendering is blocked by the alert function.
While placing JavaScript resources at the bottom of the HTML remains a standard best practice, the method by itself is sub-optimal for eliminating render-blocking scripts from the critical path.
Continue to use this method for critical scripts, but explore other solutions to truly defer non-critical scripts.
Use The Async Or Defer Attribute
The async attribute signals to the browser to load JavaScript asynchronously, and fetch the script when resources become available (as opposed to pausing HTML parsing).
Once the script is fetched and downloaded, HTML parsing is paused while the script is executed.
How the browser handles JavaScript with an async attribute. (Image from Bits of Code, August 2024)
The defer attribute signals to the browser to load JavaScript asynchronously (same as the async attribute) and to wait to execute JavaScript until the HTML parsing is complete, resulting in additional savings.
How the browser handles JavaScript with a defer attribute. (Image from Bits of Code, August 2024)
Both methods are relatively easy to implement and help reduce the time the browser spends parsing HTML (the first step in page rendering) without significantly changing how content loads on the page.
Async and defer are good solutions for the “extra stuff” on your site (social sharing buttons, a personalized sidebar, social/news feeds, etc.) that are nice to have but don’t make or break the primary user experience.
Use A Custom Solution
Remember that annoying JS alert that kept blocking my page from rendering?
Adding a JavaScript function with an “onload” resolved the problem once and for all; hat tip to Patrick Sexton for the code used below.
The script below uses the onload event to call the external resource “alert.js” only after all the initial page content (everything else) has finished loading, removing it from the critical path.
JavaScript onload event used to call alert function
Rendering of visual content was not blocked when a JavaScript onload event was used to call alert function.
This isn’t a one-size-fits-all solution. While it may be useful for the lowest priority resources (i.e., event listeners, elements in the footer, etc.), you’ll probably need a different solution for important content.
Work with your development team to find the best solution to improve page rendering while maintaining an optimal user experience.
Use CSS Media Queries
CSS media queries can unblock rendering by flagging resources that are only used some of the time and setting conditions on when the browser should parse the CSS (based on print, orientation, viewport size, etc.).
All CSS assets will be requested and downloaded regardless but with a lower priority for non-blocking resources.
Example CSS media query that tells the browser not to parse this stylesheet unless the page is being printed.
When possible, use CSS media queries to tell the browser which CSS resources are (and are not) critical to render the page.
Methods To Prioritize Critical Resources
Prioritizing critical resources ensures that the most important elements of a webpage (such as CSS for above-the-fold content and essential JavaScript) are loaded first.
The following methods can help to ensure your critical resources start loading as early as possible:
Optimize when critical resources are discovered. Ensure critical resources are discoverable in the initial HTML source code. Avoid only referencing critical resources in external CSS or JavaScript files, as this creates critical request chains that increase the number of requests the browser has to make before it can even begin to download the asset.
Use resource hints to guide browsers. Resource hints tell browsers how to load and prioritize resources. For example, you may consider using the preload attribute on fonts and hero images to ensure they are available as the browser starts rendering the page.
Considering inlining critical styles and scripts. Inlining critical CSS and JavaScript with the HTML source code reduces the number of HTTP requests the browser has to make to load critical assets. This technique should be reserved for small, critical pieces of CSS and JavaScript, as large amounts of inline code can negatively impact the initial page load time.
In addition to when the resources load, we should also consider how long it takes the resources to load.
Reducing the number of critical bytes that need to be downloaded will further reduce the amount of time it takes for content to be rendered on the page.
To reduce the size of critical resources:
Minify CSS and JavaScript. Minification removes unnecessary characters (like whitespace, comments, and line breaks), reducing the size of critical CSS and JavaScript files.
Enable text compression: Compression algorithms like Gzip or Brotli can be used to further reduce the size of CSS and JavaScript files to improve load times.
Remove unused CSS and JavaScript. Removing unused code reduces the overall size of CSS and JavaScript files, decreasing the amount of data that needs to be downloaded. Note, that removing unused code is often a huge undertaking, requiring significantly more effort than the above methods.
TL;DR
The critical rendering path includes the sequence of steps a browser takes to convert HTML, CSS, and JavaScript into visual content on the page.
Optimizing this path can result in faster load times, improved user experience, and increased Core Web Vitals scores.
Tools like PageSpeed Insights, Lighthouse, and WebPageTest.org help identify potentially render-blocking resources.
Defer and async HTML attributes can be leveraged to reduce the number of render-blocking resources.
Resource hints can help ensure critical assets are downloaded as early as possible.
More resources:
Featured Image: Summit Art Creations/Shutterstock