Author: Hanpeng_Chen

Public account: Front-end geek technology

Previous article “Browser Rendering Flow” Do you know how HTML, CSS, and JS files are converted to pages in the browser? We learned about the browser’s page rendering process, and at the end of the article we mentioned two concepts related to the rendering process: rearrangement and redraw. Understanding these two concepts will help us greatly when we do Web performance optimization.

Rearrangement (reflow)

concept

When an element’s geometry is updated, the browser needs to recalculate the element’s geometry to place it in the correct position on the interface, a process called rearrangement, also known as “backflow.”

For example, if we change the width and height of an element using JS or CSS, the browser will trigger a relayout, a series of sub-stages after parsing, called rearrangement.

The node in the render tree changes, affecting the geometry of the node and causing the node position to change, which triggers the browser to rearrange and regenerate the render tree. Rearrangement means that the geometry of the nodes changes and the rendering tree needs to be recalculated and generated, causing all or part of the rendering tree to change.

Rearrangement requires updating the entire rendering pipeline, so it is also the most expensive.

Common attributes and methods that cause rearrangements

Any operation that changes the position and size of an element triggers a rearrangement. Common examples are as follows:

  • Add or remove visible DOM elements
  • Element size change
  • Content changes, such as entering text in an input box
  • Browser window size changed
  • Calculate layout information such as offsetTop and offsetLeft
  • Sets the value of the style property
  • Activate CSS pseudo-classes, such as hover
  • Query some properties or call some methods

Geometric properties

Geometric properties: including layout, size and other properties that can be measured by mathematical geometry.

  • Layout: display, float, position, list, table, Flex, columns, grid
  • Size: margin, padding, border, width, height

Properties or methods to get layout information

The properties for getting layout information are as follows:

  • OffsetTop, offsetLeft, offsetWidth, offsetHeight
  • ScrollTop, scrollLeft, scrollWidth, scrollHeight
  • ClientTop, clientLeft, clientWidth, clientHeight
  • getComputedStyle()
  • getBoundingClientRect()

Now, some of you might be wondering, well, we just took these values and didn’t change them, so why did that trigger a rearrangement?

Modern browsers are smart enough to optimize the reordering process by queuing changes and executing them in batches, since each reordering incurs an additional computation cost. The browser queues changes until a certain amount of time has passed or a threshold has been reached. But! When you get the layout information, it forces the queue to empty because there may be operations that affect the values in the queue. To give us the most accurate values, the browser will immediately rearrange + redraw.

Avoid frequent use of these attributes.

Rearrangement of the sphere of influence

The browser rendering interface is based on the streaming layout model, so when rearranging is triggered, it rearranges the surrounding DOM in two ways:

The global scope

Rearrange the entire render tree, starting with the root node HTML.

<body>
  <div class="hello">
    <p><strong>Name:</strong>BDing</p>
    <h5>male</h5>
    <ol>
      <li>loving</li>
    </ol>
  </div>
</body>
Copy the code

When the P node in the code above is rearranged, its parent div and body nodes are also rearranged, and even the H5 and OL nodes are affected.

Local scope

Rearrange a part of the render tree or a render object.

For example, writing down the geometry of a DOM element and then triggering a rearrangement within the DOM element will only re-render the elements inside the DOM element, leaving the outside world untouched.

Redraw (repaint)

concept

The process of redrawing an element without changing its layout is called redrawing. For example, change the background color of some elements.

The redraw does not change the geometry of the element, so it goes straight to the draw phase and then performs a series of subsequences.

Redraw eliminates the need for layout and layering, so it is more efficient than rearranging.

Rearrangement is always accompanied by redrawing, but redrawing is not necessarily accompanied by rearrangement.

Appearance attributes

Includes interface, text, and other properties that can be described by state vectors

  • Interface: Appearance, outline, background, mask, box-shadow, box-reflect, filter, opacity, clip, border-radius, background-size, visibility
  • Text: text, font, word

Performance optimization

Rearrangement and redraw occur frequently when manipulating node styles, and there are significant performance issues. The cost of rearrangement is much higher than that of drawing, because the rearrangement of a node may lead to the rearrangement of child nodes, sibling nodes or ancestor nodes, so we should minimize the number of rearrangements and the rearrangement scope.

Use visibility:hidden to replace display: None

Here are four ways to see the difference:

  • Placeholder performance

    • Display: None: does not occupy space
    • Visibility :hidden: Occupy space
  • Triggering effect

    • Display :none: Triggers rearrangement and redrawing
    • Visibility :hidden: Trigger redraw
  • The transition effect

    • Display :none: effect Transitions do not affect animations
    • Visibility: Hidden: Transitions and animations will not be affected
  • Every effect

    • Display: None: itself and its children are not visible
    • Visibility :hidden: Both itself and its child nodes are not visible, but the child node can be declared to be visible separately

Avoid Table layouts

A small change in the Table layout can cause the entire Table to be rearranged.

Labels such as UL, LI, and SPAN can be used to generate tables instead of table labels

Avoid setting multiple inline styles

When the CSS parser of the browser parses THE CSS file, the CSS rules are matched from right to left. Too many style layers affect the efficiency of rearranging and redrawing.

<style>
  span {
    color: red;
  }

  div > a > span {
    color: red;
  }
</style>

<div>
  <a href="https://www.baidu.com">
    <span>Baidu search</span>
  </a>
</div>
Copy the code

For the first style, the browser just needs to find all the SPAN tags on the page and set the color, but for the second style, the browser needs to find all the SPAN tags, then find the A tag on the SPAN tag, and finally find the div tag. Then color span tags that match this condition, and the recursive process becomes complicated. So we should avoid writing too specific CSS selectors as much as possible, and add as few meaningless tags to THE HTML as possible to keep the hierarchy flat.

Set nodes that are frequently redrawn or rearranged as layers

After we built the layout tree in the previous article, we layered the page into layers that would not affect each other unless they were associated with each other.

Therefore, when frequently rearranged or redrawn nodes are set to a new layer in the browser, the new layer prevents the node’s rendering behavior from affecting other nodes.

How to set the new layer:

  • Set the node to video or iframe
  • Add the will-change attribute to the node

Use requestAnimationFrame as the animation frame

The faster the animation, the more rearranges, the browser refreshes at 60Hz, or every 16.6ms, and requestAnimationFrame() updates at 16.6ms. So you can use requestAnimationFrame() instead of setInterval().

For complex animation effects, use absolute positioning to keep them out of the document flow

For complex animation effects, which often cause rearrangement and redrawing, we can use absolute positioning to take it out of the document flow. This can cause frequent rearrangements of parent elements and subsequent elements.

Dynamically change classes without changing styles

Don’t try to change node styles every time you manipulate the DOM, as this will trigger rearrangements too often.

A better approach is to pre-define node styles with new class names, collect and confirm the final set of class names as the logical operation is performed, and dynamically replace the original set of class names once and for all when appropriate.

See the HTML DOM element attribute classList for an example.

Avoid triggering synchronous layout events

Let’s start with the following code:

for (let i = 0; i <100; i++) {
  const top = document.getElementById('list').style.top;
  console.log(top)
}
Copy the code

As we mentioned earlier, when we access some attributes of an element, the browser forces the queue to be emptied and the layout to be synchronized.

The above code rearranges the DOM each time the loop manipulates it, so you should use variables outside the loop to hold some DOM mapped values that don’t change.

const top = document.getElementById('list').style.top;
for (let i = 0; i <100; i++) {
  console.log(top)
}
Copy the code

Batch modify DOM

When we need to make a series of DOM changes, we can reduce the number of rearrangements and redraws by following these steps:

    1. Takes the element out of the document flow
    1. Modify it multiple times
    1. Bring the element back into the document.

The first and third steps of the process may cause a rearrangement, but after the first step, any changes to the DOM will not cause a rearrangement because it is no longer in the rendering tree.

There are three ways to take the DOM out of document flow:

  • Hide the DOM to manipulate

Hide the DOM with display until you want to manipulate it, and then make the display property of the DOM visible when the operation is complete, because invisible elements do not trigger rearrangements and redraws.

  • Creating a DOM fragment using a DocumentFragment, batching the DOM on it, and then adding it to the document only triggers a rearrangement.

  • Copy the node, work on the copy, and then replace it.

Of course, we can also use frameworks to modify the DOM in batches, such as Vue and React.

CSS3 Hardware acceleration (GPU acceleration)

CSS3 hardware acceleration allows animations such as transform, opacity, and filters to be redrawn without causing rebeats. However, other animation properties, such as background-color, can still be redrawn, but it can still improve the performance of these animations.

Common CSS properties that trigger CSS3 hardware acceleration are:

  • transform
  • opacity
  • filters
  • will-change

Starting hardware acceleration Notes:

  • Using CSS3 hardware acceleration for too many elements can lead to large memory footprint, which can also lead to performance issues on the other hand
  • Anti-aliasing will not work on GPU rendering fonts. This is because GPU and CPU algorithms are different. So if you don’t turn hardware acceleration off at the end of the animation, the font will blur.

Let’s use the following example to verify the optimization method of CSS3 hardware acceleration:

<body>
  <style>
    #container {
      width: 300px;
      height: 300px;
      position: absolute;
      border: 1px solid burlywood;
    }

    .rect {
      width: 100px;
      height: 100px;
      left: 0;
      top: 0;
      background-color: gray;
    }

    .animate .rect {
      animation: run-around 4s ease-in-out infinite;
    }

    @keyframes run-around {
      0% {
        transform: translate3d(0.0.0);
      }

      25% {
        transform: translate3d(200px.0.0);
      }

      50% {
        transform: translate3d(200px.200px.0);
      }

      75% {
        transform: translate3d(0.200px.0); }}</style>

  <script>
    function start() {
      const el = document.getElementById("container")
      el.classList.contains('animate')? el.classList.remove('animate') : el.classList.add('animate')}</script>

  <button onclick="start()">Start/stop animation</button>
  <div id="container">
    <div class="rect"></div>
  </div>
</body>
Copy the code

Performance in Chrome captures the rearrangement redraw over time as follows:

No rearrangement or redrawing takes place while the animation is in progress.

conclusion

Through the above learning, we can sum up the following points:

  • The rearrangement is triggered by a change in the element’s geometry
  • Redraw is triggered by a change in the draw attribute of an element
  • Triggering rearrangement does not necessarily trigger redrawing, triggering redrawing does not necessarily trigger rearrangement
  • Rearrangement costs more than redrawing
  • The basic idea of Web performance optimization is to reduce the number and scope of rearrangement

This is the end of the article. Do you already know what rearrangement and redrawing are? Why does reducing rearrangement redraw optimize Web performance? Welcome to comment.