๐Ÿ“– Getting Back To The Basics - How Browser Reads HTML, CSS, and JavaScript?

What happens when a browser loads a website?

  1. It fetches the HTML page (index.html)
  2. Begin parsing the HTML
  3. The parser encounters a tag referencing an external script file.
  4. The browser requests the script file. Meanwhile, the parser blocks and stops parsing the other HTML on your page.
  5. After some time the script is downloaded and subsequently executed.
  6. The parser continues parsing the rest of the HTML document.

(Step 4) It causes a bad user experience. Your website basically stops loading until you've downloaded all scripts. If there's one thing that users hate it's waiting for a website to load.

Speeding Up - CSS & JS Delivery

If you want DOM to get parsed as fast as possible after the user had requested the page, some things you could do is turn your javascript asynchronous and optimize loading of stylesheets which if used as usual, slow down page load due to being loaded in parallel, "stealing" traffic from the main HTML document.

To make pages load faster, limit the size of the data (HTML markup, images, CSS, JavaScript) that is needed to render the above-the-fold content of your page. There are several ways to do this:

  1. Structure your HTML to load the critical, above-the-fold content first

    • Load the main content of your page first. Structure your page so the initial response from your server sends the data necessary to render the critical part of the page immediately and defer the rest.
    • This may mean that you must split your CSS into two parts: an inline part that is responsible for styling the visible portion of the content, and the part that can be deferred.
  2. Reduce the amount of data used by your resources

    • Minify Resources: HTML
    • Consider using CSS instead of images where possible
    • Enable Compression

1. Optimize CSS Delivery

1.1 Overview - Before the browser can render content it must process all the style and layout information for the current page. As a result, the browser will block rendering until external stylesheets are downloaded and processed, which may require multiple roundtrips and delay the time to first render.

1.2 Recommendations

  • If the external CSS resources are small, you can insert those directly into the HTML document, which is called inlining.
  • Keep in mind if the CSS file is large, completely inlining the CSS may cause PageSpeed Insights to warn that the above-the-fold portion of your page is too large.
  • In the case of a large CSS file, you will need to identify and inline the CSS necessary for rendering the above-the-fold content and defer loading the remaining styles until after the above-the-fold content.
  • Don't inline large data URIs
  • Donโ€™t inline CSS attributes

2. Optimize JS Delivery

2.1 Overview Any script can insert its own HTML via document.write() or other DOM manipulations. This implies that the parser has to wait until the script has been downloaded & executed before it can safely parse the rest of the document. After all, the script could have inserted its own HTML into the document. However, most javascript developers no longer manipulate the DOM while the document is loading. So the big question occurs to the mind is Where can you put your javascript script tags and why?

2.2 Recommendations The old approach to solve this problem was to put <script> tags at the bottom of your <body>, because this ensures the parser isn't blocked until the very end.

This approach has its own problem: the browser cannot start downloading the scripts until the entire document is parsed. For larger websites with large scripts & stylesheets, being able to download the script as soon as possible is very important for performance.

If your website doesn't load within 2 seconds, people will go to another website.

In an optimal solution, the browser would start downloading your scripts as soon as possible, while at the same time parsing the rest of your document.

The modern approach Today, browsers support the async and defer attributes on scripts. These attributes tell the browser it's safe to continue parsing while the scripts are being downloaded.

async <script type="text/javascript" src="path/to/script1.js" async> </script> <script type="text/javascript" src="path/to/script2.js" async> </script>

Scripts with the async attribute are executed asynchronously.

This means the script is executed as soon as it's downloaded, without blocking the browser in the meantime.

This implies that it's possible that script 2 is downloaded & executed before script 1. According to caniuse(script-async), 90% of all browsers support this.

defer <script type="text/javascript" src="path/to/script1.js" defer> </script> <script type="text/javascript" src="path/to/script2.js" defer> </script>

Scripts with the defer attribute are executed in order (i.e. first, script 1. Then, script 2). This also does not block the browser.

Unlike async scripts, defer scripts are only executed after the entire document has been loaded.

According to caniuse(script-defer), 90% of all browsers support this. 92% support it at least partially.

An important note on browser compatibility: in some circumstances IE <= 9 may execute deferred scripts out of order. If you need to support those browsers, please read this first!

2.3 Conclusion The current state-of-the-art is to put scripts in the tag and use the async or defer attributes. This allows your scripts to be downloaded asap without blocking your browser. The good thing is that your website should still load correctly on the 20% of browsers that do not support these attributes, while speeding up the other 80%.

[Bonus] Render-tree Construction, Layout, and Paint

  • The DOM and CSSOM trees are combined to form the render tree.
  • Render tree contains only the nodes required to render the page.
  • Layout computes the exact position and size of each object.
  • The last step is paint, which takes in the final render tree and renders the pixels to the screen.