- 重排(Reflow):当浏览器发现元素的几何属性(如位置、大小、布局等)发生变化时,需要重新计算元素在页面中的位置和大小,并更新整个页面的布局,这个过程称为重排,也叫回流。
- 重绘(Repaint):当元素的外观发生变化,但不影响其在页面中的布局时,浏览器只需要重新绘制该元素,这个过程称为重绘。例如,改变元素的颜色、背景色、边框样式等,只会触发重绘。重排一定会触发重绘。
# 何时发生重排重绘
改变页面元素的大小、位置、是否隐藏都会触发重排:
页面首次渲染。
浏览器窗口大小发生改变。
元素尺寸或位置发生改变元素内容变化(文字数量或图片大小等等)。
元素字体大小、字体样式变化。
添加或者删除可见的DOM元素。
激活CSS伪类(例如:hover)。
一些常用且会导致回流的属性和方法,因为这些都要去计算位置或大小:
原因:浏览器为了避免连续多次操作导致布局树的修改重复计算位置信息,会合并这些操作,因此改动属性造成的reflow是异步的,如果此时使用JS获取布局属性,浏览器会直接reflow以便获取到最新位置信息。
clientWidthclientHeightclientTopclientLeftoffsetWidthoffsetHeightoffsetTopoffsetLeftscrollWidthscrollHeightscrollTopscrollLeftscrollIntoView()scrollIntoViewIfNeeded()scrollTo()getComputedStyle()getBoundingClientRect()
改变外观、风格不影响布局,则触发重绘:
- 修改颜色
color。 - 修改边框样式、背景颜色、背景图片。
- 文字对齐方式
text-decoration。 outline(即使改变粗细也不会重排)。
# 减少回流和重绘
最小化重绘和重排
由于重绘和重排可能代价比较昂贵,因此最好就是可以减少它的发生次数。为了减少发生次数,我们可以合并多次对DOM和样式的修改,然后一次处理掉。
const el = document.getElementById('test'); el.style.padding = '5px'; el.style.borderLeft = '1px'; el.style.borderRight = '2px'; // 大部分现代浏览器都对其做了优化,因此,只会触发一次重排。 // 使用cssText el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;'; // 修改CSS的class el.className += ' active';1
2
3
4
5
6
7
8
9
10批量修改DOM
当我们需要对DOM对一系列修改的时候,可以通过以下步骤减少回流重绘次数:
- 使元素脱离文档流 => 对其进行多次修改 => 将元素带回到文档中。
该过程的第一步和第三步可能会引起回流,但是经过第一步之后,对DOM的所有修改都不会引起回流,因为它已经不在渲染树了。
有三种方式可以让DOM脱离文档流:
- 隐藏元素,应用修改,重新显示。
- 使用文档片段(document fragment,
document.createDocumentFragment)在当前DOM之外构建一个子树,再把它拷贝回文档。 - 将原始元素拷贝到一个脱离文档的节点中,修改节点后,再替换原始的元素。
避免触发同步布局事件
访问元素的一些属性的时候,会导致浏览器强制清空队列,进行强制同步布局。
对于复杂动画效果,使用绝对定位让其脱离文档流
对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流。否则会引起父元素以及后续元素频繁的回流。
css3硬件加速(GPU加速)
- 使用css3硬件加速,可以让
transform、opacity、filters这些动画不会引起回流重绘。 - 对于动画的其它属性,比如
background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。
css3硬件加速的坑
- 如果你为太多元素使用css3硬件加速,会导致内存占用较大,会有性能问题。
- 在GPU渲染字体会导致抗锯齿无效。这是因为GPU和CPU的算法不同。可能CSS3的动画会产生字体模糊。
常见的触发硬件加速的css属性(最好用
transform,animations):transformanimationstransitionopacityfilterswill-change
- 使用css3硬件加速,可以让