preface

Redraw and reflow are old questions, and they are often asked in interviews. From the change of the style of a DOM element in a page to the display of a page by entering a URL into the browser, they are all involved. Today, I will talk about them and consolidate my knowledge.

The browser’s rendering process

When the browser process delivers the requested response body data to the renderer process, it generates a DOM tree by parsing HTML, and a CSSOM tree by parsing CSS. Then it starts from the root node of the DOM tree and finds every visible node in the DOM tree (script, link, meta tags are not visible). For each visible node, find the corresponding style from the CSSOM tree, and finally generate a rendering tree based on the combination of each visible node and the corresponding CSS style.

Layout and repainting

After the render tree generation, the need to calculate the render tree each node in the viewport corresponding to the location and size of the device, and the calculation process is back, in the process is completed, by each node in the render tree and styles, and they are relative to the viewport equipment geometry information, through re-paint, at this time we have got a node absolute pixels. Finally, the pixels are sent to the GUI, and a page is formed. To sum up:

  • Layout(backflow): According to the generated rendering tree, backflow (Layout), get node geometry information (location, size).
  • Painting(repainting): Get absolute pixels of nodes based on the rendered tree and geometry information from backflow.

When do redraws and reflow occur?

  • Redraw: When the style of a page element changes without affecting the geometry of the node in the document flow, such as color

  • Return: when a page element geometry properties or layout changes, such as add or delete the DOM elements, change the position of the element, element size change (inner and outer margin, border, wide high, etc.), content changes, such as text changes, image is replaced by another a picture of a different size, the browser window size changes

Backflow always causes redraw, redraw does not necessarily cause backflow

Browser queue optimization mechanism

Modern browsers do not perform every backflow redraw. Instead, they queue operations that involve backflow redraw. After a period of time or when the queue is full, the browser executes all operations in the queue at once, greatly reducing backflow redraw times and improving performance. However, the queue will be forced to refresh when the code execution needs to obtain the location information of some elements (for example, when executing some jS apis to obtain the location information). These apis include: ClientWidth, clientHeigth, clientLeft, clientTop, ScrollWidth, scrollHeight, scrollLeft, scrollTop, getBoundingClientRect()…

How to reduce backflow and redraw

css

  • Use transform instead of TOP (CSS hardware-accelerated, less layout delay)
  • Common CSS properties that trigger hardware acceleration: transform, opacity, filters, will-change
  • Avoid table layouts
  • Try to avoid multi-layer nesting, structure as flat as possible
  • DOM elements with complex animation effects should be kept separate from the flow of the document
  • Use opacity, opacity instead of display: none (the former only involves redrawing, while the latter requires backflow)

js

  • Setting a CSS style for a DOM element avoids setting it line by line (for example: Width = ’40px’, el.style.color = ‘red’), can be set centrally with cssText, or first set the style class in CSS, using JS directly add the class name.
  • There are three steps involved in bulk DOM modification (1): Take the DOM element to be modified out of the document flow. (2): It has been modified for several times. (3): Bring the DOM element back into the document flow.
  • For the above methods involving batch DOM modification, there are probably one of the following:

(1) First set the display element to None, then modify it, and finally redisplay it

(2) Create a subtree outside the current document stream using createDocumentfragment() and insert it back into the document.

(3) Copy the original element to a separate node, modify the node, and then replace the original element (API: copy cloneNode(), replace replaceChild()))

The last point

If you want to call the force-refresh queue API inside the loop, you can use a variable outside the loop to fetch and save, and then operate on the variable inside the loop to avoid backflow every time