In 2018, the average time to fully load a mobile page was 15 seconds. That is substantially higher than Google’s recommended page load time of 3 seconds.
So, of course, reducing the total load time remains a top priority for allowing user interaction as quickly as possible.
But page speed isn’t only about total page load time; it’s also about what users experience in those 3 (or 15) 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.0 below).
There’s a whole process on how to do this, outlined in Google’s developer guide documentation (thank you, Ilya Grigorik), but I’ll be focusing on one heavy hitter in particular: reducing render-blocking resources.
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.
How Do I Optimize It?
Improving the critical rendering path involves identifying and analyzing your critical resources (any resource that blocks the initial rendering of the page), and looking 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.
This article will focus on step 1 – deferring render-blocking resources (i.e., rearranging elements for efficiency to make it feel like the experience is faster without removing stuff).
Why Should I Care?
Well, no one puts it more frankly than the hundred-dollar man himself:
“Time is money.” – Benjamin Franklin
Google’s user behavior data reports that most users abandon a slow site after about 3 seconds.
On the contrary, a page speed study by Unbounce found that nearly three-quarters of consumers said that they were willing to wait 4 seconds or more for a page to load.
What gives?
“Time is an illusion.” – Albert Einstein
A study published by the Journal of Consumer Research indicated that there are two types of time:
- Objective time: Standard clock time.
- Subjective time: Consumer’s perception of time.
Focusing too heavily on objective time can be problematic, as humans (and our real-life users) are notoriously bad at estimating time.
“Time flies when you’re having fun.” – My Dad
People’s perception of time is based on a variety of subjective factors.
Of these includes whether they are in “passive wait” or “active wait.” In terms of page rendering, these can be defined as:
- Passive wait: User is looking at a blank white screen
- Active wait: Visual content is rendering on the page
Research published by INFORMS found that, even when wait times are measurably equal, people in passive wait overestimate their time spent waiting by +36%.
The same concept inspired the widespread use of the progress (or loading) bar in computing, as it was found to reduce anxiety, creating a more positive experience for users.
“Web pages don’t have loading bars. So when the page is slow, the visitor doesn’t know if the delay will be another 500 milliseconds or 15 seconds. Maybe it will never load. And the back button is right there” (Andy Crestodina, Orbit Media quoted by Unbounce).
With many studies linking reductions in page load times to improvements in valuable KPIs (conversions, bounce rate, time on site), improving site latency has become a top-of-mind business goal for many organizations.
SEO professionals are in a unique position to guide this effort, as our role is often to bridge the gap between business goals and web developer’s priorities.
Having the ability to audit a site, analyze results, and identify areas for improvement helps us to work with developers to improve performance and translate results to key stakeholders.
Back to Render-Blocking Resources
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.
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.
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.
Official Google 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
Wait, what about 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).
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.
Official Google 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 to Identify Render-Blocking Resources
To identify the critical rendering path and analyze critical resources:
- Run a test using 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.
After identifying a (potentially) render-blocking resource, test removing it to see if above-the-fold content is affected.
In my example, I noticed some JavaScript requests to the Google Maps API that don’t appear to be critical. But it’s a good idea to test removing these scripts to test how shifting elements on the site affects the experience.
To test within the browser on 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.
Methods to Reduce Render-Blocking
Once you have confirmed a resource is not critical to render above-the-fold content, explore different methods available to defer resources and improve 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>.
Circling back to my example using a JavaScript alert function, the higher up the function is in the HTML, the sooner it will be downloaded and executed by the browser.
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, 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.
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.
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” event (from Patrick Sexton on Varvy.com) resolved the problem once and for all.
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.
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 located below-the-fold.
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.
When possible, use CSS media queries to tell the browser which CSS resources are (and are not) critical to render the page.
TL;DR
- The goal of optimizing the critical rendering path is to provide users with meaningful content as quickly as possible.
- Deferring render-blocking CSS and JavaScript allows important, above-the-fold content to render faster.
- To identify render-blocking resources:
- Look for non-critical resources loading before the start render line (via webpagetest.org).
- Test removing resources via Google Dev Tools to see how page content is affected.
- Once identified, work with developers to find the best solution to defer render-blocking resources.
More Resources:
Image Credits
Featured Image: Screenshot taken by author, July 2019
All screenshots taken by author, July 2019