Web page rearrangement (reflow) is one of the important reasons for hindering fluency. Combined with the article What forces layout / reflow and the reference, we will sort out the causes and optimization thinking of reflow.
To borrow this classic picture:
Web page rendering will go through DOM -> CSSOM -> Layout (rearrangement or reflow) -> Paint (redrawing) -> Composite (compositing), of which Composite has been introduced in detail in the intensive reading "In-depth Understanding of Modern Browsers 4" , which is in GPU Rasterize.
Then, except for the performance problems that JS, DOM, CSSOM, and Composite may cause, the rest is the focus of our attention this time, reflow. It can be seen from the sequence that redrawing must be done after reordering, and redrawing does not necessarily trigger reordering.
Overview
When will Layout(reflow) be triggered? Generally, when the element position changes. But it's not always the case, because the browser will automatically merge the changes. After reaching a certain number or time, it will be merged into a reflow, and reflow is an important step in rendering the page. Opening the browser will definitely reflow at least once, so we can't Avoid reflow.
So why pay attention to the performance problems caused by reflow? This is because some codes may cause browser optimization failure, that is, it is not merged when reflow can be merged. This usually occurs when we use the js API to access the size of an element. In order to ensure that the exact value is obtained, it has to be triggered in advance. A reflow, even if written in a for loop.
Of course, reflow is not triggered every time the element location is accessed. After the browser triggers reflow, snapshots of all existing element locations will be recorded. As long as the location and other changes are no longer triggered, reflow will not be triggered when the location is accessed for the second time. One point will be expanded in detail later. Now to explain, what exactly is this "trigger position and other changes"?
According to the summary of the What forces layout / reflow document, there are several categories:
Get box model information
-
elem.offsetLeft
,elem.offsetTop
,elem.offsetWidth
,elem.offsetHeight
,elem.offsetParent
-
elem.clientLeft
,elem.clientTop
,elem.clientWidth
,elem.clientHeight
-
elem.getClientRects()
,elem.getBoundingClientRect()
Some means of obtaining the element's position, width and height will lead to reflow, and there is no bypass, because as long as this information is obtained, it must be reflowed to give an accurate value.
scroll
-
elem.scrollBy()
,elem.scrollTo()
-
elem.scrollIntoView()
,elem.scrollIntoViewIfNeeded()
-
elem.scrollWidth
,elem.scrollHeight
-
elem.scrollLeft
,elem.scrollTop
Access and assignment
For scrollLeft
assignment is equivalent to triggering scrollTo
, all the behaviors that cause scrolling will trigger reflow, the author checked some information, the main speculation is that the appearance of the scroll bar will cause the visible area to change. Narrow, so reflow is required.
focus()
-
elem.focus()
( source )
You can look at the comments according to the source code, mainly this paragraph:
// Ensure we have clean style (including forced display locks).
GetDocument().UpdateStyleAndLayoutTreeForNode(this)
That is, when focusing on an element, although there is no requirement to obtain the element position information, the element to be focused may be hidden or removed. At this time, UpdateStyleAndLayoutTreeForNode
rearrange and redraw the function must be called to ensure the state of the element. Updates to continue.
There are some other element APIs:
-
elem.computedRole
,elem.computedName
-
elem.innerText
( source )
innerText
also needs to be rearranged to get the correct content.
Get window information
-
window.scrollX
,window.scrollY
-
window.innerHeight
,window.innerWidth
-
window.visualViewport.height
/width
/offsetTop
/offsetLeft
source code )
Like the element level, in order to get the correct width and height and position information, it must be rearranged.
document related
-
document.scrollingElement
Redraw only -
document.elementFromPoint
elementFromPoint
Because to get the exact position of the element, it must be rearranged.
Form related
-
inputElem.focus()
-
inputElem.select()
,textareaElem.select()
focus
, select
trigger rearrangements similar to elem.focus
.
mouse event related
-
mouseEvt.layerX
,mouseEvt.layerY
,mouseEvt.offsetX
,mouseEvt.offsetY
( source )
The calculation of the relative position of the mouse must rely on a correct arrangement, so the reflow must be triggered.
getComputedStyle
getComputedStyle
usually causes rearrangement and repainting. Whether or not the rearrangement is triggered depends on factors such as access to position-related keys.
Range related
-
range.getClientRects()
,range.getBoundingClientRect()
Get the size of the selected area, you must reflow to ensure accuracy.
SVG
A large number of SVG methods will cause rearrangement, so I won't enumerate them one by one. In short, when using SVG operations, you should be as careful as operating DOM.
contenteditable
In elements set to contenteditable
, many operations, including copying images to the clipboard, can cause rearrangements. ( source )
intensive reading
What forces layout / reflow Here are a few related articles about reflow, and the author picks a few important ones to summarize.
repaint-reflow-restyle
repaint-reflow-restyle mentioned that modern browsers will combine multiple dom operations, but other kernel browsers such as IE do not guarantee such an implementation, so a safe writing method is given:
// bad
var left = 10,
top = 10;
el.style.left = left + "px";
el.style.top = top + "px";
// better
el.className += " theclassname";
// or when top and left are calculated dynamically...
// better
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
For example, a modification of the className, or a modification of cssText
ensures that the browser must trigger a reflow. But this will reduce the maintainability a lot and is not recommended.
avoid large complex layouts
Avoid large complex layouts emphasizes the separation of read and write, first look at the following bad case:
function resizeAllParagraphsToMatchBlockWidth() {
// Puts the browser into a read-write-read-write cycle.
for (var i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.width = box.offsetWidth + 'px';
}
}
Constantly accessing the element width and modifying its width in the for loop will cause the browser to perform N reflows.
Although all the old layout values from the previous frame are known when the JavaScript is running, when you make changes to the layout, all layout values from the previous frame are cached, so the next time you get the value, you have to Re-trigger the reflow once.
The separation of read and write means centralized reading. Although the number of reads is still so many, data can be obtained from the layout cache from the second time without triggering reflow.
It is also mentioned that flex layout is much faster than traditional float rearrangement (3ms vs 16ms), so try not to use float for layouts that can be done with flex.
really fixing layout thrashing
really fixing layout thrashing mentioned to practice read-write separation with fastdom :
ids.forEach(id => {
fastdom.measure(() => {
const top = elements[id].offsetTop
fastdom.mutate(() => {
elements[id].setLeft(top)
})
})
})
fastdom
is a library that can separate read and write execution without separating code, especially suitable for reflow performance optimization scenarios. Each measure
and mutate
will be pushed into the execution queue and executed at window.requestAnimationFrame timing.
Summarize
Backflow cannot be avoided, but it needs to be controlled within the normal frequency range.
We need to learn which properties or methods to access will lead to backflow. If you can’t use it, don’t use it, and try to separate reading and writing. When defining elements that will trigger frequent reflows, try to keep them out of the document flow to reduce the impact of reflows.
The discussion address is: Intensive Reading "web reflow" Issue #420 dt-fe/weekly
If you'd like to join the discussion, click here , there are new topics every week, with a weekend or Monday release. Front-end intensive reading - help you filter reliable content.
Follow Front-end Intensive Reading WeChat Official Account
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
Copyright notice: Free to reprint - non-commercial - non-derivative - keep attribution ( Creative Commons 3.0 license )
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。