本篇文章参考以下博文
回流重绘比较
浏览器渲染 | 特点 | 消耗 | 常见操作 |
---|---|---|---|
重绘 | 页面样式的改变不影响布局,只需要UI层面重新像素绘制 | 较小 | 改变元素颜色,改变背景色 |
回流 | 浏览器重新渲染界面,需要重新布局 | 较重 | 页面初次渲染 窗口大小改变 元素尺寸/位置/内容发生变化 增加删除可见元素 |
回流必定会触发重绘,重绘不一定会触发回流。
为了提高页面性能,其中一个思路就是减少浏览器的回流,这个可以关联到之前的两篇文章,下面这两个方法是减少回流的经典案例。
浏览器渲染过程
回到正题,我们需要先了解一下浏览器的渲染过程。
- 首先浏览器向服务端发送请求,请求到了 html 文件和 css 文件。
- 然后分别解析两个文件, html 解析成 Dom tree, css 解析成 cssom 样式结构体。
- 然后 Dom tree 和 cssom 结合,产生 render tree。
这个 render tree 就是我们看到的页面了。了解 React 或者 Vue 的同学应该不陌生,在这两个框架中,当页面变化的时候,会生成一个 Virtual Dom 然后根据 diff算法 来获取其中变化的部分,替换变化的部分后,就形成了新的 render tree。 这也是一个经典的回流过程。
如何减少回流重绘
减少开销,有一个核心思想, 能换就绝对不修,必须要修的时候拆下来修,而不是直接在手机上修,把各种 dom 操作,想象成修手机,摄像头坏了,不修,直接拿个新的换上,屏幕坏了,不修,也直接拿个新的换上,主板坏了,必须要修了,先把主板卸下来,修好之后再安回去。
① 需要修改某些样式的时候,不是直接获取元素,然后修改样式,而是直接给元素换一个 class 。
el.className += " className1";
② 使用 cssText 修改样式
el.style.cssText += `; left: ${left} px; top: ${top} px;`;
③ 先让元素脱离 render tree 修改好之后,再添加回去。只有两次回流
el.style.display = 'none'; //一次回流
...//各种操作
el.style.display = 'block'; //两次回流
④ 当多次使用 offsetWidth 和 offsetHeight 等属性的时候(offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() )先读取到变量中进行缓存。