【Editor's Note】In fact, there are many articles about web page rendering, but the relevant information is scattered and the discussion is not very complete. If we want to have a general understanding of this topic, we still have to learn a lot. Therefore, web developer Alexander Skutin decided to write an article. He believes that this article can not only help beginners, but also be beneficial to advanced front-end developers who want to refresh their knowledge structure. The original address
The translation is as follows:
Web page rendering must be carried out at a very early stage, which can be as early as the page layout has just been finalized. Because styles and scripts will have a critical impact on web page rendering. Therefore, professional developers must know some techniques to avoid encountering performance problems in practice.
This article will not study the detailed mechanism inside the browser, but propose some general rules. After all, different browser engines work differently, which will undoubtedly make developers' research on browser features more complicated.
How does the browser complete web page rendering?
First, let’s review the actions of the browser when rendering a web page:
form the Document Object Model (DOM) based on the HTML code from the server side
load and parse styles to form the CSS object model.
On top of the document object model and CSS object model, create a rendering tree consisting of a set of objects to be rendered (in Webkit these objects are called renderers or rendering objects, and in Gecko they are called "frame".) The render tree reflects the structure of the document object model, but does not contain invisible elements such as tags or with the display:none attribute. In the render tree, each text string is represented by an independent renderer. Each render object contains its corresponding DOM object, or text block, plus calculated styles. In other words, the render tree is a visual representation of the document object model.
For each element in the rendering tree, calculate its coordinates, which is called layout. Browsers use a flow approach, laying out an element in one pass, but table elements require multiple passes.
Finally, the elements on the rendering tree are finally displayed in the browser. This process is called "painting".
When the user interacts with the web page, or the script program changes and modifies the web page, some of the operations mentioned above will be performed repeatedly because the internal structure of the web page has changed.
Redraw
When changing the style of elements that do not affect the position of the element in the web page, such as background-color (background color), border-color (border color), visibility (visibility), the browser will only Redraw the element with the new style (this is redrawing, or re-structuring the style).
Reflow
Reflow or rearrangement occurs when changes affect text content or structure, or element positioning. These changes are usually triggered by the following events:
DOM operations (element addition, deletion, modification, or change of element order);
Content changes, including text changes within form fields;
CSS property calculations or changes;
Add or remove stylesheets;
Change properties of "classes";
Manipulation of browser windows (zoom, scroll);
Pseudo-class activation (:hover).
How does the browser optimize rendering?
Browsers try to limit redraw/reconstruction to the area of the changed element as much as possible. For example, for an element with a fixed or absolute position, the size change only affects the element itself and its sub-elements. However, the size change of a statically positioned element will trigger the reflow of all subsequent elements.
Another optimization technique is that when running several pieces of JavaScript code, the browser will cache these changes, and then apply these changes in a single pass after the code has finished running. For example, the following code will only trigger a refactor and repaint:
var $body = $('body'); $body.css('padding', '1px'); // reflow, repaint $body.css('color', 'red'); // repaint $body.css('margin', '2px'); // reflow, repaint // only 1 reflow and repaint will actually happen
However, as mentioned before, changing the properties of the element will trigger a forced reflow. This behavior will happen if we add a line of code to the above code block to access the element's properties.
var $body = $('body'); $body.css('padding', '1px'); $body.css('padding'); // reading a property, a forced reflow $body .css('color', 'red'); $body.css('margin', '2px');
The result is that the reflow occurs twice. Therefore, you should group operations that access element attributes together to optimize web page performance. (You can find more detailed examples on JSBin)
Sometimes, you have to trigger a forced reflow. For example, we must assign the same attribute (such as left margin) to the same element twice. Initially, it should be set to 100px with no animation. Next, it must be changed to 50px via a transition animation. You can follow this example on JSbin right now, but I'll cover it in more detail here.
First, we create a CSS class with transition effect: .has-transition { -webkit-transition: margin-left 1s ease-out; -moz-transition: margin-left 1s ease-out; -o-transition: margin-left 1s ease-out; transition: margin-left 1s ease-out; }
Then continue: // our element that has a "has-transition" class by default var $targetElem = $('#targetElemId' );
// remove the transition class $targetElem.removeClass('has-transition'); // change the property expecting the transition to be off, as the class is not there // anymore $targetElem.css('margin-left', 100); // put the transition class back $targetElem.addClass('has-transition'); // change the property $targetElem.css('margin-left', 50);
However, this execution fails to work. All changes are cached and only executed at the end of the code block. What we need is a forced reordering, which we can achieve with the following changes:
// remove the transition class $(this).removeClass('has-transition');
// change the property $(this).css('margin-left', 100); // trigger a forced reflow, so that changes in a class/property get applied immediately $(this)[0].offsetHeight; // an example, other properties would work, too // put the transition class back $(this).addClass('has-transition'); // change the property $(this).css('margin-left', 50);
Now the code executes as expected .
Practical Advice on Performance Optimization
Summarizing the available information, I offer the following advice:
Create valid HTML and CSS files, and don’t forget to indicate how the document is encoded. Styles should be included within the tag, and script code should be added at the end of the tag.
Simplify and optimize CSS selectors as much as possible (this optimization method is almost uniformly ignored by developers using CSS preprocessors) and keep nesting to a minimum. Here is the performance ranking of CSS selectors (starting with the fastest)
1. 识别器:#id 2. 类:.class 3. 标签:div 4. 相邻兄弟选择器:a + i 5. 父类选择器:ul> li 6. 通用选择器:* 7. 属性选择:input[type="text"] 8. 伪类和伪元素:a:hover
You should remember that browsers process selectors from right to left, so the rightmost selector should be the fastest: #id or .class: div * {...} // bad .list li {...} // bad .list-item {...} // good #list .list-item {... } // good * 1. In your script code, reduce DOM operations as much as possible. Cache everything, including element attributes and objects if they are reused. When performing complex operations, it is better to use "isolated" elements, which can be added to the DOM later (the so-called "isolated" elements are elements that are separated from the DOM and only stored in memory).
2. If you use jQuery to select elements, please follow jQuery selector best practices.
3. In order to change the style of an element, modifying the "class" attribute is one of the effective methods. When performing this change, the deeper you are in the DOM rendering tree, the better (it also helps to decouple logic from presentation).
4. Try to only add animation effects to elements with absolute or fixed positions.
5. Disable complex hover animations when using scrolling (for example, add an additional non-hover class in). Readers can read an article on this issue.
If you want to know more details, you can also read these two articles:
1, How browsers work?
2,Rendering: repaint, reflow/relayout, restyle