⬆️ ⬇️

Critical way of rendering web pages

In the web developer environment, knowledge of the importance of speed is becoming increasingly common. Many try to speed up: they use gzip compression, minification, caching headers, shortening requests, optimizing images, and others.



After the implementation of these recommendations, the question arises: what exactly are we optimizing? It turns out that in most cases this is the time of full page load with all elements. However, this is not exactly what you need. Actually, the time for which the user gets the “first screen” of the page with important functional elements (title, text, product description, etc.) is important. In other words, the moment of the start of the page rendering is important. This is where the critical rendering path arises, which determines all the actions that the browser must perform to begin page rendering. With this thing we will understand the article.



What is the critical path?



The critical rendering path is a set of actions, resources, and calculations that are minimally necessary to start a page.



The critical path can be measured in the amount of critical resources, the minimum load time (measured in RTT) and the volume of critical resources (in bytes).

')

To illustrate, take the simplest example: an HTML page of 1 KB in size without external resources. The critical path will be: 1 resource (HTML document), 1 RTT (minimal), 1 kb of traffic. However, there are almost no such simple pages in nature, so we will show how you can determine the critical path on real web pages.



Critical path determination



This web page consists of an HTML document and a number of external resources: CSS files, JS files, fonts, images, etc. Modern browsers are trying to optimize the page loading process as much as possible in order to start rendering as soon as possible. However, browsers are limited to CSS and JS specifications, so they must build the page in strict sequence. The final stage of the critical path is the construction of the Render Tree, by which the browser can start rendering.



Let's look at the basic steps that the critical path includes:

  1. Get the html document.
  2. Parsing HTML for included resources.
  3. Build a DOM tree (document object model).
  4. Send requests for critical items.
  5. Get all the CSS code (also run requests for JS-files).
  6. Build CSSOM tree.
  7. Execute all received JS-code.
  8. Rebuild DOM tree (if necessary).
  9. Build a Render tree and start rendering the page.


From this sequence, several important conclusions can be drawn.



Firstly, resources with CSS and JS-code are involved in the critical path. The remaining external resources are not counted there.

Secondly, the JS code cannot be executed until all CSS resources are received and the CSSOM tree is not built.

Thirdly, the page cannot be rendered before the JS code is executed, since it can change the DOM tree.

But not everything is so simple: the matter, as usual, is in the details. Our task: to minimize the critical rendering path for our page.



Ways to shorten the critical path



For example, let's take the page code from the demonstration of the Autocomplete plugin from jQuery UI.



<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>jQuery UI Autocomplete - Default functionality</title> <link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="http://code.jquery.com/jquery-1.10.2.js"></script> <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <link rel="stylesheet" href="http://jqueryui.com/resources/demos/style.css"> <script> $(function() { var availableTags = [ "ActionScript", "AppleScript", "Scheme" ]; $( "#tags" ).autocomplete({ source: availableTags }); }); </script> </head> <body> <div class="ui-widget"> <label for="tags">Tags: </label> <input id="tags"> </div> </body> </html> 


What are the elements of the critical path of this page?



Provided that JS files are loaded in parallel, we get 3 RTT (minimum).

Reduce the critical rendering path. What can be done in this case:



It should be noted that the first two optimizations are relevant only when using regular HTTP without SPDY or HTTP / 2, in which the number of requests does not matter. Since the bright future (HTTP / 2) is not far off, and SPDY is already present, we will not deal with gluing files together.



Let us dwell on the third and fourth optimization. Moving the JS file call to the end of the document will allow the browser to start rendering the page earlier. Deferred loading of CSS from jQuery UI is possible due to the fact that styles from this file are needed only to display the autocomplete element (after typing in the box).



This is how the final version of the page will look like.



 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>jQuery UI Autocomplete - Default functionality</title> <link rel="stylesheet" href="http://jqueryui.com/resources/demos/style.css"> </head> <body> <div class="ui-widget"> <label for="tags">Tags: </label> <input id="tags"> </div> <script>document.addEventListener("DOMContentLoaded", function(event) { var availableTags = [ "ActionScript", "AppleScript", "Scheme" ]; $( "#tags" ).autocomplete({ source: availableTags }); }); </script> <script>document.addEventListener("DOMContentLoaded", function(event) { $('head').append('<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" type="text/css">'); });</script> <script src="http://code.jquery.com/jquery-1.10.2.js"></script> <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> </body> </html> 


Notice: the jQuery UI plugin calls are wrapped in a construct:



 document.addEventListener("DOMContentLoaded", function(event) { // plugin code }); 


This allows you to place code that depends on jQuery and its plug-ins anywhere on the page. The deferred loading of a CSS file was performed using the same method.



Now the critical path is shortened by 1 request (CSS) and it does not require loading (traffic) to start drawing. Due to the fact that the entire JS-code is moved to the end of the document, the browser can start drawing before the execution of this code.

If there are scripts on the page that can be executed later (for example, counter scripts, social plugins, etc.), then you can throw them out of the critical rendering path with the async attribute:



 <script src=1.js async></script> 


However, this is not possible with jQuery and its plugins (there is an asynchronous loading method, but it is rather dreary). Therefore, we use the solution described above.



Result



Checking what happened. Download both files to Chrome. Open Developer tools, enable “Toggle device mode”, limit the network to 450 Kbps 150 ms RT, download without cache. When loading, we are on the “Timeline” tab.



We are interested in the moment of the start of the page drawing (the first Paint events, they are displayed in green). For non-optimized version: 5000 ms, for an optimized 500 ms.



Using the techniques described, you can significantly speed up the rendering of your pages, especially if they are saturated with JS-functionality and have a large amount of CSS-code. When making optimizations, be careful: test every change - changing the order of loading the JS libraries can break the functionality.



What to read more



Source: https://habr.com/ru/post/262239/



All Articles