参考:https://muyiy.cn/question/browser/22.html
一、浏览器渲染的过程
- 解析HTML,构建DOM树。解析CSS,构建CSSOM树
- DOM树和CSSOM树结合,生成渲染树
- 回流(Layout):根据生成的渲染树进行回流,得到节点的几何信息(大小和位置)
- 重绘(Painting): 根据渲染树以及已经得到的回流信息,得到节点的绝对像素。
- 将像素发送给GPU,展现在页面上
二、什么时候会发生回流与重绘
回流这一阶段主要是计算位置与几何信息,所以当页面布局和几何信息发生变化的时候就需要回流 。比如以下情况
- 页面一开始渲染的时候
- 浏览器的窗口发生变化(会重新计算位置和大小)
- 添加或删除可见的DOM元素
- 元素的大小(width,height,margin,padding,border-width),位置发生变化
- 内容发生变化(如图片的url改变)
只发生重绘的情况:改变一些只影响元素外观的样式,而不影响布局(如background改变)
三、浏览器触发回流与重绘
当浏览器获取布局信息时,由于要获取最新的布局信息,所以浏览器不得不清空队列,触发回流重绘来返回准确的值。如修改下面的值:
- offset~ (offsetTop、offsetLeft、offsetWidth、offsetHeight)
- scroll~ (scrollTop、scrollLeft、scrollWidth、scrollHeight)
- client~ (clientTop、clientLeft、clientWidth、clientHeight)
- getComputedStyle()
- getBoundingClientRect
三、如何减少回流与重绘
1.合并多次对样式的修改
如:
1 2 3 4 | const el = document.getElementById('test'); el.style.padding = '5px'; el.style.borderLeft = '1px'; el.style.borderRight = '2px'; |
可以使用
1 2 | const el = document.getElementById('test'); el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;'; |
或者通过改变className改变样式
1 2 | const el = document.getElementById('test'); el.className += ' active'; |
2. 批量修改DOM
如:
1 2 3 4 5 6 7 8 | function appendDataToElement(appendToElement, data) { let li; for (let i = 0; i < data.length; i++) { li = document.createElement('li'); li.textContent = 'text'; appendToElement.appendChild(li); } } |
上面代码每一次循环都添加了DOM元素,所以导致了很多次的回流与重绘
所以可以先创建完所有的元素后一次性添加
1 2 3 4 | const ul = document.getElementById('list'); const fragment = document.createDocumentFragment(); appendDataToElement(fragment, data); ul.appendChild(fragment); |
3.避免触发同步布局事件
上文我们提到过,访问一些属性时会导致浏览器强制清空队列,如使用offsetWidth:
1 2 3 4 5 | function initP() { for (let i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = box.offsetWidth + 'px'; } } |
上面代码每一次循环都访问了offsetWidth,所以导致了很多次的回流与重绘
所以我们要尽量减少访问这类属性
1 2 3 4 5 6 | function initP() { const width = box.offsetWidth; for (let i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = width + 'px'; } } |
4.对于复杂动画效果,使用绝对定位让其脱离文档流
5.css3硬件加速(GPU加速)
比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘。
- 使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。
- 对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。