Remove blocking JavaScript and CSS

Jun 05, 2015

External file references in web page like: JavaScript and CSS may block page rendering. They force the browser to wait for the files to be downloaded, parsed and execute. Assuming that there is a JavaScript file reference which needs 2 seconds to be loaded, then the browser will stop rendering until the JS file is loaded after 2 seconds. We need to eliminate any potential blocking external JavaScript and CSS files when optimize web page.

JavaScript

Why does it block rendering?

<!doctype html>
<html>
  <head>
    <script type="text/javascript" src="page.js"></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

When the HTML parser encounters the script tag above, the browser doesn't know what the script is planning to do on the page, hence it has to pause DOM construction, download the script and let the script execute before proceeding with DOM construction. If there is a latency when downloading the script, the whole page rendering will be impacted as well.

Inline JavaScript

If page.js is essential to initial page render, you can inline the contents directly into the HTML document to avoid the network request latency.

<!doctype html>
<html>
  <head>
    <script type="text/javascript">
    /* contents of page.js */
    </script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

Defer script loading

If the loading and execution of page.js are unnecessary for the initial page render, you can defer the loading of page.js, let it to be loaded after DOM construction.

<!doctype html>
<html>
  <head>
  </head>
  <body>
    <h1>Hello World</h1>
    <script type="text/javascript" src="page.js"></script>
  </body>
</html>

Asynchronous loading

In HTML5, you can add attribute: "async" to script tag, this tell the browser that the script doesn't need to execute at the exact point where it is referenced in the document. The browser will continue to construct the DOM and let the script execute once it's downloaded.

<!doctype html>
<html>
  <head>
    <script type="text/javascript" src="page.js" async></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

However you cannot make one JS file asynchronous if it is required by other JS file(s).

<!doctype html>
<html>
  <head>
    <script type="text/javascript" src="jquery-1.11.3.min.js" async></script>
    <script type="text/javascript" src="jq-plugin.js" async></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

The script execution is no longer sequential after adding "async" attribute. In above code, jq-plugin.js requires jQuery. If jq-plugin.js is loaded before jQuery, it will fail to execute as jQuery is not ready at the moment. Such issue can be resolved by using dependency management, I will not expand it cause it's another topic.

CSS

CSS file stores all the style and layout information for the DOM elements. As a result, the browser will block rendering until external stylesheets are downloaded and processed.

Inline CSS

If the CSS codes are essential to initial page render, you can inline the content directly into the HTML document as well.

<!doctype html>
<html>
  <head>
    <style tpe="text/css">
    .blue {
        color: blue;
    }
    </style>
  </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
  </body>
</html>

Defer CSS loading

If the CSS codes are unnecessary for initial page render, you can defer the CSS file loading, let it to be loaded after DOM construction.

<!doctype html>
<html>
  <head>
    <style tpe="text/css">
    .blue {
        color: blue;
    }
    </style>
  </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
    <link href="other.css" rel="stylesheet" />
  </body>
</html>

Summary

We should let browser show the page content to user as soon as possible. We can inline the code of all essential script and stylesheets into HTML document directly and let other external files to be loaded after DOM construction.