To understand backflow and redraw, you must first understand the browser rendering process
Browser rendering process
- Critical rendering path: The process by which the browser initially receives HTML,CSS,JavaScript, etc., and then parses, builds the tree, renders the layout, draws, and finally presents the interface to the client.
- The actual user sees only two phases :DOMContentLoaded(when the page content is loaded) and Load(when the page resources are loaded).
- Page content loaded: When the DOMContentLoaded event is triggered, only the DOM has been loaded, not the stylesheets, images, etc
- Page resources loaded: When the load event is triggered, all the DOM, style sheets, and script images on the page have been loaded
- The browser rendering looks like this:
- Illustration:
- The browser parses the requested HTML document into a DOM tree.
- Each CSS file is analyzed into a StyleSheet Object. Each Object contains a StyleSheet Object that contains CSS rules. The CSS rule object contains selectors and declaration objects corresponding to the CSS syntax, among other objects.
- Attchment: Combine the DOM Tree and CCSSOM (Attchment) to generate a Render Tree. The generated Render objects wait for rendering (through the DOM Tree and CSS rule Tree, the browser can build the Render Tree through both of it. The browser first iterates through each visible node, starting at the root of the DOM tree, and then finds and applies the appropriate CSS style rules for each visible node.
- Layout: The content of each element in the rendered tree is calculated to obtain the geometric information (location, size) of the node, which is called Layout. The layout phase starts at the root node of the Render tree. Since each node is a Render Object, it contains style information such as width, height, position, background color and so on. So the browser can use this style information to determine the exact size and location of each node object on the page. The output of the layout phase is known as the box model, which captures the exact location and size of each element on the screen.
- Painting: Derive the absolute pixels of the nodes based on the geometry of the rendered tree and the backflow, then paint each node of the rendered tree onto the screen (painting)
- Display: Sends pixels to the GPU for Display on the page. (This step is actually a lot of content, such as the GPU will be multiple composition layer into a single layer, and displayed in the page. Css3 hardware acceleration is based on a new composition layer.
- Note: The above steps do not have to be done in the order of a row. If the DOM or CSSOM is modified, or some of the steps may be repeated, during normal development, JavaScript operations and CSS assignments often change the DOM or CSSOM multiple times.
The process,
-
Build a DOM tree
- DOM trees can be blocked by CSS and JS loads during construction
- Elements for display: None will also be in the DOM tree
- Comments and SCRIPT tags are in the DOM tree
- The next sibling of the current node is built only when all the children of the current node are built
-
Build CSSOM tree
- CSS parsing and DOM parsing can be performed simultaneously
- CSS parsing and script execution are mutually exclusive
- Script execution is optimized in the Webkit kernel so that mutual exclusion only occurs when JS accesses CSS
-
Building the render tree
- The render tree does not correspond exactly to the DOM tree (the render tree contains only visible nodes)
- Display: None elements are not in the render tree
- Visibility: The element hidden is in the render tree
- After the rendering tree is generated, it needs to get the position information of each node through the processing of Layout
-
Layout of the Render Tree
- Detaching from the document stream is essentially detaching from the render tree
- Float elements, absoulte elements, and fixed elements will be displaced, also known as out of the document stream
-
Painting the Render Tree
- During the draw phase, the browser traverses the rendered tree and calls the renderer’s paint() method to display its contents on the screen. The rendering of the rendered tree is done by the browser’s UI back-end component
So that’s the basics, and with that in mind, let’s talk about reflow and repaint.
Reflux and redraw (reflow)
The default layout of the DOM is a streaming layout, but javascript and CSS can break this layout, changing the DOM’s appearance, size, and position, so you have reflow and repaint and reflow always triggers redraw, but redraw doesn’t necessarily backflow
Reflow
- By constructing the render tree, you combine the visible DOM nodes and their corresponding styles, but you also need to calculate their exact location and size within the device viewport. The stage of this calculation is circumventing. To figure out the exact size and location of each object on the site, the browser starts at the root of the render tree
- Of course, when the browser realizes that the layout has changed, it needs to go back and rerender. This process is called reflow
- In fact, when the page is first rendered, it is called backflow. My understanding is that the blank page before the page is rendered actually has content, and from “white space” to the element display is called backflow and redraw
Repaint
- By constructing the render tree and the reflux stage, we know which nodes are visible, the style of the visible nodes and the specific geometric information (location, size), so we can transform each node of the render tree into an actual pixel on the screen. This stage is called redrawing
When Reflow and Repaint Occur
- First rendering of the page (initialization)
- DOM tree changes (e.g., adding or deleting nodes)
- Render tree changes (e.g., padding changes)
- Resize the browser window
- Get certain attributes and methods of an element (for example)
- OffsetTop, offsetLeft, offsetWidth, offsetHeight
- ScrollTop, scrollLeft, scrollWidth, scrollHeight
- ClientTop, clientLeft, clientWidth, clientHeight
- getComputedStyle()
- GetBoundingClientRect () returns the size of the element and its position relative to the viewport
- Background color, color, font changes (note: backflow is triggered when font size changes)
- Specific can access the site: gist.github.com/paulirish/5… (May not open, can refresh several times to try)
- Backflow must cause a T redraw, which can be triggered separately
Optimization mechanisms for browsers
Modern browsers are smart enough to optimize the reordering process by queuing changes and executing them in batches, since each reordering incurs additional computational costs. The browser queues changes until a certain amount of time has passed or a threshold has been reached. But! When you retrieve layout information, you force the queue to refresh. For example, the retrieve property and action method above both return the latest layout information, so the browser has to clear the queue and trigger a backflow redraw to return the correct value. Therefore, it is recommended that we avoid using the attributes listed above when changing styles, as they all refresh the render queue. ** If you want to use them, it is best to cache the values.
Reduce backflow and redraw
-
Css3 Hardware Acceleration (GPU Acceleration)
- You can make transform, opacity, and filters animations that do not cause backflow redraw
- The will-change attribute (unused)
-
Avoid changing the style of each node individually and try to change it all at once (using cssText or changing the CSS class)
const el = document.getElementById('test'); el.style.padding = '5px'; el.style.borderLeft = '1px'; el.style.borderRight = '2px'; // Avoid the above, below suitable const el = document.getElementById('test'); el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px; ' const el = document.getElementById('test'); el.className += ' active'; Copy the code
-
Use the DocumentFragment to cache the DOM elements that need to be modified several times, and finally append them to the real DOM for rendering once
function appendDataToElement(appendToElement, data) { let li; for (let i = 0; i < data.length; i++) { li = document.createElement('li'); li.textContent = 'text'; appendToElement.appendChild(li); }}const ul = document.getElementById('list'); const fragment = document.createDocumentFragment(); appendDataToElement(fragment, data); ul.appendChild(fragment); Copy the code
-
You can set the DOM element that needs to be modified several times to display: None. (Because the hidden element is not in the render tree, modifying the hidden element does not trigger a backflow redraw)
function appendDataToElement(appendToElement, data) { let li; for (let i = 0; i < data.length; i++) { li = document.createElement('li'); li.textContent = 'text'; appendToElement.appendChild(li); }}const ul = document.getElementById('list'); ul.style.display = 'none'; appendDataToElement(ul, data); ul.style.display = 'block'; Copy the code
-
Avoid reading certain properties multiple times (avoid triggering synchronous layout events)
function initP() { for (let i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = box.offsetWidth + 'px'; }}// The latter is much better than the former const width = box.offsetWidth; function initP() { for (let i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = width + 'px'; }}Copy the code
-
The complex node elements are separated from the document flow by absolute displacement to form a new Render Layer and reduce the backflow cost
function appendDataToElement(appendToElement, data) { let li; for (let i = 0; i < data.length; i++) { li = document.createElement('li'); li.textContent = 'text'; appendToElement.appendChild(li); }}const ul = document.getElementById('list'); const clone = ul.cloneNode(true); appendDataToElement(clone, data); ul.parentNode.replaceChild(clone, ul); Copy the code
-
For complex animation effects, use absolute positioning to take them out of the document stream
conclusion
There are so many things to learn at the front end, one step at a time, come on, by the way, remember to click like, thank you