How to fix high total blocking time

Jacquelyn Tandang
Jacquelyn Tandang
Jun 17, 2023

In our previous post, blog#6, serving our images from a content delivery network (CDN) drastically improved our page speed performance to a perfect 100 using the Lighthouse Chrome browser extension.

LCP after changes in blog#6

Your internet service provider's (ISP) network performance plays a huge role in measuring the performance of a webpage. In our test, we used a home wifi with the following speed.

Page speed test

Performance may not be the same for users in a slower connection such as those in mobile devices connected to mobile data.

How to test performance using average mobile data speed?

You can test your page's performance on normal 4G network speeds at https://pagespeed.web.dev

Simulated 4G connection speed

Below is the performance of our web page when served on a 4G connection. We have a total blocking time of 220ms.

Performance on 4G

Total Blocking Time

A browser cannot interrupt a task that's in progress (i.e. running javascript, downloading styles in an external file). When a user interacts with the page in a middle of a long task, the browser must wait for the task to finish before it can respond preventing input responsiveness hence called 'blocking'[1].

The user will likely notice the delay if the task is long enough and will perceive the page as sluggish.

To provide a good user experience, sites should strive to have a Total Blocking Time of less than 200 milliseconds when tested on average mobile hardware.

Total blocking time affects 30% of the performance score making it the top metric to optimize.

How to lessen Total Blocking Time

There are several ways you can do to decrease total blocking time.

1. Asynchronous downloading of scripts

When the browser loads HTML and comes across an inline script tag, it can't continue building the DOM. It must execute the script right now.

<script>...</script>

The same happens for external scripts, the browser must wait for the script to download, and execute the downloaded script, and only then can it process the rest of the page[2].

<script src="..."></script>

Adding an 'async' attribute in your external scripts tells the browser not to wait for the script. The browser will continue to process the HTML, loading the script in the background, and will execute the script once it has been downloaded.

<script async src="..."></script>

To improve total blocking time, whenever possible, move inline scripts to an external file and add the async attribute to download the file asynchronously.

2. Defer execution of scripts where possible

Adding a 'defer' attribute in your external scripts will also download the script asynchronously but will wait for the DOM to finish loading before executing.

<script defer src="..."></script>

This option is good for scripts that are not needed before the page loads.

3. Load styles as needed

Just like scripts, inline stylesheets and external stylesheets are blocking.

<styles>...</styles>
<link rel="stylesheet" href="mystyle.css"> 

Unfortunately, unlike javascript, stylesheets has no async and defer loading options.

To help lessen blocking time due to loading and executing stylesheets, we can divide the styles into 2 parts.

3.1. Critical CSS

These are styles that are used in above-the-fold content. In blog#4, we defined above-the-fold as the part of the web page that is visible before the user scrolls down the page.

Since these styles are needed right away, they will need to be loaded right away. These styes should be included inline. This way, there is no need to spend time to download the styles from an external source and can be executed right away.

3.2. Non-critical CSS

These are styles that are not used above-the-fold. They will not be seen until the user scrolls the page therefore can be loaded at a later time.

Since scripts can be loaded asynchronous but the styles cannot, suggest to load all async/defer javascripts before the non-critical styles. Placing the non-crtical styles right before the closing body tag makes sure that everything has already been loaded and no more tasks will be blocked, avoiding critical request chain.

4. Minify both Javascripts and CSS

Minification is the process of minimizing code and markup in your web pages and script files[3]. By minimizing the code, the files become smaller, improving downloading time.

Case Study

Travel Cheap Asia is built on Laravel. Using Laravel Mix, a package providing an API for defining webpack build steps for your Laravel application[4], javascripts and css files are minified.

By configuring Tailwind CSS as a postcss plugin in Laravel Mix, we further minified our css files to further reduce our file size. Unlike javascript, css has no option to load async or defer therefore, we would like our styles to have the smallest filesize possible.

All our javascript files were already deferred but we are still getting 220 ms total blocking time.

Methodology

We have already divided our css into critical and non critical styles however, our critical styles are loaded from external files requiring download time before execution.

Chaining critical requests before

Moving our styles inline improved our critical path latency and improved our performance score by 1 point.

Performance after moving critical css inline Chaining critical requests after moving critical css inline

Our non-critical css is only 1.69KiB which is quite small. Having it on an external file may do more harm than good. On slower internet speeds, we might have a longer downloading time. Moving it inline, we removed overhead to have to download this small file.

Moreover, our non-critical css was loaded before our javascript files blocking our scripts to be loaded asynchronously.

After moving our non-critical css inline and loading it after the javascript files, right before our body tag, we have totally eliminated chaining critical requests further improving our performance score by another 1 point.

Performance after moving non-critical css inline after the async javascripts

Results

By including the critical CSS inline and loading our non-critical CSS just before the body tag, right after our asynchronous scripts, we have improved our total blocking time from 220 ms to 40ms when viewing web pages on mobile devices on a 4G mobile data network.

Sources:
[1] https://web.dev/tbt/
[2] https://javascript.info/script-async-defer
[3] https://www.imperva.com/learn/performance/minification/
[4] https://laravel.com/docs/9.x/mix