First, build a DOM tree
The input for building a DOM tree is a very simple HTML file, which is parsed by an HTML parser and finally outputs the DOM as a tree structure.
Recalculate Style
The purpose of style calculation is to calculate the specific style of each element in a DOM node.
Just like HTML files, browsers don’t understand the CSS styles of plain text directly, so when the rendering engine receives CSS text, it performs a conversion operation that transforms the CSS text into styleSheets that browsers can understand.
StyleSheets computes the specific style of each node in the DOM tree: ComputedStyle
3. Stage Layout & Layer
Now, we have the DOM tree and the styles of the elements in the DOM tree, but that’s not enough to display the page because we don’t yet know the geometry of the DOM elements. The next step is to figure out the geometry of the visible elements in the DOM tree, a process we call layout.
Chrome performs two tasks in the layout phase: creating a layout tree and creating a layout layer.
-
1. Create a Layout tree
You may have noticed that the DOM tree also contains many invisible elements, such as the head tag and elements that use the display: None attribute. So, before displaying, we also build an additional layout tree with only visible elements.
Let’s look at the layout tree construction process with the following figure:
-
2. Lay out the Layer Layer
Now that we have the layout tree and the exact location of each element calculated, is it time to start drawing the page? NO!
-
layered
Because there are many complex effects on the page, such as complex 3D transformations, scrolling, or z-indexing, the rendering engine will need to generate a LayerTree for each node to make it easier to achieve these effects.
The relationship between layout tree and layer tree:
-
4. Layer rendering
After building the layer tree, the rendering engine draws each layer in the tree.
When the drawing list is ready, the main thread commits the drawing list to the composition thread.
-
Synthesis of the thread
The compositing thread will divide the layer into tiles, which are usually 256×256 or 512×512, as shown below:
The composition thread then prioritizes bitmap generation based on the blocks near the viewport, and the actual bitmap generation is performed by rasterization. Rasterization refers to the transformation of a map block into a bitmap. The graph block is the smallest unit for rasterization. The renderer maintains a rasterized thread pool, where all rasterization is performed, as shown below:
In general, GPU rasterization is used to speed up bitmap generation.
A rasterized thread pool is essentially a “processing plant” that converts blocks into bitmaps.
-
Composition and display
Once all the tiles have been rasterized, the composition thread generates a command to draw the tiles — “DrawQuad” — and submits the command to the browser process.
At this point, through this series of stages, the HTML, CSS, JavaScript, etc., written by the browser will display a beautiful page.
Rendering assembly line summary
From HTML to DOM, styling, layout, layering, drawing, rasterization, composition, and display. Here’s a diagram to summarize the entire rendering process:
Combined with the above image, a complete rendering process can be summarized as follows:
- The renderer transforms the HTML content into a readable DOM tree structure.
- The rendering engine translates CSS styleSheets into styleSheets that browsers can understand, calculating the style of DOM nodes.
- Create a layout tree and calculate the layout information for the elements.
- Layer the layout tree and generate a hierarchical tree.
- Generate a draw list for each layer and submit it to the composition thread.
- The composite thread divides the layer into blocks and converts the blocks into bitmaps in the rasterized thread pool.
- The composite thread sends the DrawQuad command to the browser process.
- The browser process generates the page from the DrawQuad message and displays it on the monitor.
Relevant concepts
Let’s look at three more concepts related to the rendering pipeline — “rearrange”, “redraw” and “compose”.
This can be very helpful in optimizing Web performance.
1. The rearrangement of reflow
Updated the geometry of the element.
As you can see from the above figure, if you modify the geometry of an element using JavaScript or CSS, such as changing the width, height, etc., then the browser will trigger a rearrangement of the layout, followed by a series of sub-stages called rearrangement. Of course, reordering requires updating the entire rendering pipeline, so it’s also the most expensive.
2. Redraw repaint
Updates the draw attribute of the element.
As can be seen from the figure, if you change the background color of the element, the layout stage will not be performed, because there is no change in the geometry position, so you directly enter the drawing stage, and then perform a series of subsequent stages, this process is called redraw. Redraw eliminates layout and layering, so it is more efficient than rearrange.
3. Direct synthesis stage
So what happens if you change a property that neither layouts nor draws? The rendering engine skips layout and drawing and only performs subsequent compositing operations, which we call compositing.
In the image above, we use the TRANSFORM of CSS to animate the effect, which avoids the rearrangement and redraw phases and executes the compositing animation directly on the non-main thread. This is the highest efficiency, because it is composed on the non-main thread, does not occupy the main thread resources, and avoids the layout and drawing two sub-stages, so compared with redraw and rearrangement, composition can greatly improve the drawing efficiency.
Reduced reflow/ Repaint scheme enumeration
- Don’t change the STYLE of the DOM line by line. Instead, define the CSS class in advance and change the DOM className.
// bad
var left = 10,
top = 10;
el.style.left = left + "px";
el.style.top = top + "px";
// Good
el.className += " theclassname";
// Good
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
Copy the code
- Take the DOM offline and modify it. Such as:
- Manipulate the DOM in memory using the DocumentFragment object
- Start with the DOM display: None (once reflow) and change it however you want. Like, 100 times, and then it shows up.
- Clone a DOM node into memory and change it in any way you want. When you’re done, swap it with the online one.
-
Do not put DOM node attribute values in a loop as variables in the loop.
Otherwise this will result in a lot of reading and writing of the node’s properties.
-
Modify the lower-level DOM as much as possible.
Of course, changing the DOM at the bottom of the hierarchy can cause large reflows, but it can also have small effects.
-
Use Position: Fixed or ABsoulte for the animated HTML element.
Then modifying their CSS will not reflow.
-
Never use a table layout.
Because a small change can cause the entire table to be rearranged.