Today, in the eleventh installment of the JavaScript series, we’ll talk about browser subsystems responsible for rendering web pages. They play a key role in transforming the descriptions of documents made with HTML and CSS into what we see on the screen.

The author of the material said that the company
SessionStack has to pay great attention to rendering. In this article, he will share tips on optimizing web pages, taking into account the peculiarities of their visualization.
[We advise you to read] Other 19 parts of the cycle Overview
When creating web applications, we do not write isolated JS code that deals exclusively with some kind of own “internal” affairs. This code is executed in the environment provided by the browser and interacts with it. Understanding the device of this environment, how it works, what parts it consists of, allows the developer to create better programs, gives him the opportunity to anticipate possible problems with the application that came out.
')
The figure below shows the main components of the browser. Let's talk about the role they play in the processing of web pages.
The main components of the browser- User Interface (User Interface). This browser component includes the address bar, the “Forward” and “Back” buttons, the commands for working with bookmarks, and so on. In general, this is all that the browser displays - with the exception of the area of its window, where the displayed web page is located.
- Browser Engine (Browser Engine). It supports the interaction between the user interface and the rendering engine.
- Rendering Engine (Rendering Engine). This subsystem is responsible for displaying the web page. The rendering engine processes HTML and CSS and displays what it did on the screen.
- Network subsystem (Networking). This subsystem is responsible for the network interaction of the browser with the outside world, in particular, for example, XHR requests are performed by its means. It supports a platform-independent interface that hides specific implementations of various network mechanisms specific to different platforms. Here you can read details about this subsystem.
- User Interface Support Subsystem (UI Backend). This subsystem is responsible for displaying basic interface components, such as windows and controls, such as checkboxes. Here, the browser is provided with a universal interface that does not depend on the platform on which it runs, and this subsystem is based on the possibility of generating user interface elements provided by a specific operating system.
- JavaScript engine (JavaScript Engine). We analyzed the JS engine in one of the previous materials in this series. This is where JS code is executed.
- Data Persistence Subsystem. If an application needs local data storage capabilities, it can use various mechanisms provided by this subsystem. Among them, for example, such APIs as localStorage , IndexedDB , WebSQL and FileSystem .
In this article we will focus on the rendering engine. It is this browser subsystem that parses and renders HTML and CSS. And these are the technologies with which the code of web applications written in JavaScript constantly interacts.
On various rendering engines
The main task of the rendering engine is to display the requested page in a browser window. The engine can display HTML documents, XML documents, images. When using additional plugins, the engine can visualize other types of materials, for example, PDF documents.
We know that there are different JS engines that use different browsers. The same is true for rendering engines. Here are some popular engines:
- Gecko - used in Firefox browser.
- WebKit - used in the Safari browser.
- Blink - integrated into Chrome and Opera browsers (from the 15th version).
Webpage Rendering Process
The rendering engine receives the contents of the requested document from the browser’s network layer. The rendering process looks like the one below.
Webpage Rendering ProcessHere are the main steps of this process:
- HTML processing to create a DOM tree.
- Creating a render tree.
- Calculation of the parameters of the location of the elements of the rendering tree on the screen, the formation of the page layout.
- Rendering (rendering) the rendering tree.
Consider these and other steps performed when rendering web pages in more detail.
Creating a DOM tree
The first step in the rendering engine is to parse the HTML document and convert what it did to DOM nodes located in the DOM tree. In this case, the web page, which is presented in the form of HTML code, is converted into a structure similar to that shown in the figure below.
DOM treeEach element of this tree containing nested elements is a parent for them. This is true for all levels of nesting.
Creating a CSSOM Tree
CSSOM (CSS Object Model) is a CSS object model. When the browser is creating the DOM tree of a page, it finds in the
head
section a
link
tag that refers to an external CSS file, say,
theme.css
. Expecting that he may need this resource to render the page, the browser fulfills the request to download this file. This file contains plain text, which is a description of the styles applied to the page elements.
As in the case of HTML, the engine needs to convert CSS into something the browser can work with - in CSSOM. The result is a CSSOM tree, shown in the following figure.
CSSOM treeDo you know why CSSOM has a tree structure? When the final set of styles for the page element is generated, the browser starts with the most general rules applicable to this element represented by the DOM node (for example, if the node is a child of the
body
element, all styles specified for the
body
are applied to it) and then recursively specifies computed styles by applying more specific rules.
Let us examine the example presented in the previous figure. Any text contained within the
span
tag that is placed on the
body
element is displayed in red and has a font size of
16px
. These styles are inherited from the
body
element. If the
span
element is a descendant of the
p
element, then its contents are not displayed in accordance with the more specific style applied to it.
Also note that the above tree is not a full CSSOM tree. This shows only the styles that we, in our CSS file, decided to override. Each browser has a standard style set, applied by default, also known as “user agent styles” (user agent styles). It is the results of applying these styles that can be seen on a page that has no CSS rules associated with it. Our styles simply override some of the standard browser styles.
Creating a render tree
The instructions on the appearance of elements presented in HTML, combined with information about their styling from the CSSOM tree, are used to form the rendering tree.
What it is? This is a tree of visual elements created in the order in which they will be displayed on the screen. This is a visual representation of the HTML code of the page, reflecting the influence of the CSS rules corresponding to this page. The purpose of this tree is to ensure that the elements are displayed in the correct order.
The node of the rendering tree is known in the WebKit engine as "renderer" or "render object" (we will call them "rendering objects").
Here is what the rendering tree will look like for the DOM and CSSOM trees shown above.
Rendering treeHere is a general description of the browser actions that it performs when creating the render tree.
- Starting at the root of the DOM tree, the browser traverses every visible node. Some sites are invisible (for example, tags that contain links to scripts, meta tags, and so on), their browser skips because they do not affect the appearance of the page. Some nodes are hidden by means of CSS, the browser also does not include them in the rendering tree. For example, the
span
node from our example is not displayed in the render tree, since we have an explicitly specified rule that sets the display: none
property for it.
- For each visible node, the browser finds the appropriate CSSOM rules and applies them.
- As a result, a structure is formed containing the visible nodes and the styles calculated for them.
In order to better understand what is being said here, you can take a look at the source code of the
RenderObject class from WebKit. Each rendering object is a rectangular area, usually corresponding to the CSS block of the node. Information about this block includes its geometrical characteristics, such as width, height and position.
Forming page layout
After the rendering object is created and added to the tree, it has not yet been assigned a position and size. Calculating these values is called page layout generation.
HTML uses a streaming layout model. This means that most often the system can calculate the geometric parameters of the elements in one pass. It uses a coordinate system based on the root rendering object, it uses the coordinates
left
and
top
.
Layout generation is a recursive process. It starts at the root object that corresponds to the
<html>
element of the document. The process is performed recursively throughout the hierarchical structure of the rendering object, the dimensions and position are calculated for each element that needs it.
The position of the root rendering object is
0,0
. Its dimensions correspond to the size of the visible part of the browser window (this is called the viewport).
The process of forming a layout means assigning to each node the exact position in which it should appear on the page.
Render tree rendering
At this stage, the rendering tree is traversed and the
paint()
methods of rendering objects are called, which perform the output of a graphical representation of the objects on the screen.
Visualization, or rendering, can be global or incremental (the page layout is also formed).
- Global rendering means re-rendering the entire rendering tree.
- Incremental rendering is performed in a situation where only some of the rendering objects are changed, moreover, so that it does not affect the entire tree. The rendering subsystem invalidates the rectangular areas on the screen. This leads to the fact that the operating system sees them as areas, the contents of which need to be updated and generate a
paint
event for them. The operating system performs the redrawing of areas intellectually, combining several areas into one.
In general, it is important to understand that visualization is a phased process. To improve the perception of the page by users, the rendering engine tends to display the page as soon as possible. It will not wait until all HTML has been parsed, in order to proceed to the formation of the rendering tree and the calculation of the page layout parameters. As a result, some parts of the page will be processed and displayed, while the rendering engine will continue to work with the remaining content of the page, which comes from the network.
The order of processing JS-scripts and CSS-files
The analysis and execution of the script is carried out immediately after the page code processing system reaches the
<script>
. Document processing is suspended until the script is executed. This means that this process is performed synchronously.
If the script is received from an external source, it must first be downloaded via the network (also synchronously). Page processing pauses until the script download is complete.
HTML5 allows you to indicate the possibility of asynchronous loading and processing of the script using a separate stream.
Rendering performance optimization
If you want to optimize your application, taking into account the features of page rendering, there are five main areas that you can control and which need to be addressed.
- Javascript In previous articles in this series, we talked about how to write an optimized JS code that does not block the user interface, efficiently uses memory, and implements other useful techniques. When it comes to rendering, we need to consider how the JS code will interact with the DOM elements on the page. JavaScript can make many changes to the user interface, especially when it comes to one-page applications.
- Calculation styles. This is the process of determining which CSS rule is applied to a particular element, taking into account the corresponding selectors. After determining the rules, they are applied and the final style is calculated for each element.
- Formation of the page layout. After the browser finds out which styles are applied to the element, it can begin to calculate how much space on the screen this element takes and to find its position. The layout model of a web page indicates that some elements can affect other elements. For example, the width of a
<body>
element can affect the width of the child elements, and so on. All this means that the process of forming a layout is a task that requires intensive calculations. In addition, the output elements are performed on multiple layers.
- Rendering. This is where the conversion of everything that was previously calculated to the pixels displayed on the screen is performed. This process involves the output of text, colors, images, borders, shadows, and so on. We are talking about every visible part of each element.
- Layout Since parts of the page may well be displayed on different layers, they need to be combined in a single window in the correct order, which will lead to the correct output of the page. This is very important, especially for overlapping elements.
JS code optimization
JavaScript code often leads to changes in what can be observed in the browser. This is especially true for single-page applications. Here are some tips on optimizing JS to improve the page rendering process.
- Avoid using the
setTimeout()
and setInterval()
functions to update the appearance of page elements. These functions call a callback at some point in the frame formation, perhaps at the very end. We need to call the command leading to visual changes at the beginning of the frame, and not to miss it.
- Transfer lengthy calculations to web workers .
- Use micro-tasks split into several frames to make changes to the DOM. This should be used when the task needs access to the DOM, and access to the DOM from a web worker, for example, cannot be obtained. This means that a large task needs to be broken down into smaller ones and executed within the
requestAnimationFrame
, setTimeout
, or setInterval
, depending on the specifics of the task.
CSS optimization
Modifying the DOM by adding and removing elements, changing attributes, and other similar actions will cause the browser to recalculate the styles of the elements, and, in many cases, the layout of the entire page, or at least some part of it. To optimize the page rendering process, consider the following.
- Reduce the complexity of the selectors. The use of complex selectors can lead to the fact that working with them will take more than 50% of the time required to calculate the styles of the element, the rest of the time will be spent on constructing the style itself.
- Reduce the number of elements for which you want to perform style calculations. That is, it is better if the style change is directed to several elements, and not to the whole page.
Layout optimization
Recalculation of the page layout may require serious system resources. To optimize this process, consider the following.
- Reduce the number of situations leading to recalculation of the layout. When you change styles, the browser determines whether a recalculation of the layout is required to reflect these changes. Changes in properties, such as width, height, or element position (in general, we are talking about the geometric characteristics of the elements), require changes in the layout. Therefore, unless absolutely necessary, do not change these properties.
- Whenever possible, use the flexbox model instead of older model layouts. This model is faster than others, which can give a significant performance boost.
- Avoid the model of work with the document, providing for periodic changes in the parameters of elements and their subsequent reading. In JavaScript, the parameters of DOM elements (like
offsetHeight
or offsetWidth
) from the previous frame are available. Reading these parameters does not cause problems. However, if you change the style of an element before reading such parameters (for example, dynamically adding some CSS class to it), the browser will need to spend a lot of resources in order to apply style changes, create a layout and return the necessary data to the program. This can slow down the program, like this should be avoided whenever possible.
Rendering optimization
Often this task takes the most time, so it is important to avoid situations that lead to redrawing the page. Here is what can be done here.
- Changing any property, with the exception of transformations and changes in transparency, leads to a redraw. Use these features sparingly.
- If your actions caused a recalculation of the layout, this leads to a call to redraw the page, since changes in the geometric parameters of the element also lead to its visual changes.
- Reduce the area of pages that need to be redrawn, competently controlling the location of the layers and animation.
Results
In this article we talked about the rendering subsystems of modern browsers. The right approach to page visualization leads to improved performance of web applications and improved user experience.
Previous parts of a series of articles:
Part 1:
How JS Works: Overview of the Engine, Runtime Mechanisms, Call StackPart 2:
How JS Works: About V8 Inside and Code OptimizationPart 3:
How JS works: memory management, four types of memory leaks and how to deal with themPart 4:
How JS works: event loop, asynchrony, and five ways to improve code with async / awaitPart 5:
How JS: WebSocket and HTTP / 2 + SSE work. What to choose?Part 6:
How JS Works: Features and Scope of WebAssemblyPart 7:
How JS Works: Web Workers and Five Use CasesPart 8:
How JS Works: Service WorkersPart 9:
How JS Works: Web Push NotificationsPart 10:
How JS Works: Tracking DOM Changes with MutationObserverDear readers! What techniques do you use to optimize the rendering of the pages of your web projects?
