How Browser See Webpages

How Browser See Webpages

I don't need to know how rendering works, the browser does it for me!

Introduction

As an engineer, I thought I could live without knowing how the webpage loaded in a browser, then why should I?

As a beginner, it doesn't matter if you don't know, as long as you write the code and make it usable by the users. However, as you go on an application that you build becomes larger and you start to feel it become slower and slower. To solve this problem, you need some performance tuning, but to improve something it is important to know how it works. In this case, to improve the web page on browsers it's good to know how it works.

Rendering flow

The figure below shows the flow of processing that the browser does for each frame.

process.drawio.png

For example, when the screen is initially displayed, the browser performs this processing flow from the beginning. On the other hand, when there is an update to the screen display, only the necessary processes are processed, and processes that do not require recalculation are omitted.

This means that simply knowing which changes are related to which flow can greatly reduce the burden on the browser.

Parsing

This process involves the parsing of HTML and CSS. The browser parses the HTML and CSS and converts them into easy to process structures called DOM Tree and CSS Object Model, respectively.

parsing.drawio.png

Create Render Tree

In this step, the DOM Tree created earlier is linked to the Style Rules. Specifically, which styles are applied to which elements are matched, and for elements with multiple matching styles, the final style to be applied is determined according to the priority of style application.

render-tree.drawio.png

The matching of styles and elements created here is called a Render Tree. Each element in the Render Tree is called a Renderer.

⚠️ This process will re-run each time you manipulate the DOM in Javascript, or when you change CSS properties.

Layout Render Tree

In this process, the position and size of each element are calculated. This process is called Layout or Reflow. The layout calculation is done recursively from upstream to downstream of the Render Tree to create a Layout Tree that takes the position and size information into account.

⚠️ This process will re-run when when there are layouts change (also animation) (height, width, padding, margin, top, right, left, bottom, box-shadow)

Painting UI

In the painting stage, the render tree is traversed and the renderer's "paint()" method is called to display content on the screen. Painting uses the UI infrastructure component.

CSS2 defines the order of the painting process. This is actually the order in which the elements are stacked in the stacking contexts. This order affects painting since the stacks are painted from back to front. The stacking order of a block renderer is:

  1. background color
  2. background image
  3. border
  4. children
  5. outline

Composite

Compositing is the combining of visual elements from separate sources into single images.

Painting of DOM elements gets done at numerous layers on the page. Once it is complete, the browser combines all the layers into one layer in a correct order and displays them on the screen. This process is especially important for pages with overlapping elements as the incorrect layer composition order may result in an abnormal display of the elements.

⚠️ The application of transform and opacity, which are often used in animation, is also done in this process.

Improve Performance

These are tips on how you can improve performance

Avoid Render in Deep layer

Once you understand the rendering process, you will understand the CSS properties that should be used for animation. First of all, for comfortable rendering, it is important to avoid the Layout process as much as possible and to use transform and opacity, which can be completed only in Composite. Also, to improve performance, use will-change to separate layers for Layout and Paint processes.

Example: Render in Composite Level is faster than re-rendering layout render tree. Therefore, changes to transform and opacity are much lighter than changes to layout properties (left, top, etc.).

Avoid Render Blocking

Render blocking is an event that when the browser encounters static files such as fonts, HTML, CSS, JavaScript, etc., it stops downloading the rest of the resources until these important files are processed.

For example, let's say it takes 5 seconds to load a JS file. After 5 seconds, the file will be loaded, the DOM tree will be created, and the web page will be loaded, but we don't want our users to wait for 5 seconds, right? We can solve that by loading only the files that need to be loaded, and processing the rest later. Here's how it works.

CSS

By default, CSS is treated as a render blocking resource, which means that the browser won't render any processed content until the CSSOM is constructed. Make sure to keep your CSS lean, deliver it as quickly as possible, and use media types and queries to unblock rendering.

There are ways to avoid CSS Render Block :

  1. Load CSS async-ly Make CSS Load after DOM Tree created
<script>
    (function() {
      const tag = document.createElement("link");
      tag.href = 'css/style.css';
      tag.rel = 'stylesheet';
      document.head.appendChild(tag);
    })();
</script>
  1. Add use media query
    • media="print" Used for Print preview mode/printed pages Make CSS Load after DOM Tree created
    • media="(screen)" Used for computer screens, tablets, smart-phones etc. Make CSS Load only on specified screen size
<link href="style.css" rel="stylesheet" media="print"> 
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">

JS

JavaScript allows us to modify just about every aspect of the page: content, styling, and its response to user interaction. However, JavaScript can also block DOM construction and delay when the page is rendered. To deliver optimal performance, make your JavaScript async and eliminate any unnecessary JavaScript from the critical rendering path.

There are ways to avoid JS Render Block:

  1. Load JS "async-ly" Make JS Load after DOM Tree created
  <script type="text/javascript">
    (function() {
      const script = document.createElement("script");
      script.type = "text/javascript";
      script.src = 'js/main.js';
      document.head.appendChild(script);
    })();
  </script>
  1. Put JS at end of file
<html>
  <head> .... </head>
  <body>
    ...
    <script src="js/main.js" type="text/javascript"></script>
  </body>
</html>

Summary

Once you understand the rendering process, you can improve user experience from loading time, animation, and overall performance.

Did you find this article valuable?

Support Alvin Endratno's Blog by becoming a sponsor. Any amount is appreciated!