一、引言
在前端开发中,理解回流和重绘对性能优化来说比较重要。回流和重绘是浏览器渲染页面时的两个重要过程。本文将介绍回流和重绘的概念,并提供一些优化技巧来减少其性能开销。
二、页面渲染
浏览器获取到页面资源后做了什么?
1.解析HTML:浏览器会将接收到的HTML代码解析成DOM树,构建出页面的结构。
2.解析CSS:浏览器会解析CSS代码,构建出CSSOM,表示页面的样式信息。
3.构建渲染树:浏览器会将DOM树和CSSOM合并,生成渲染树(Render Tree),渲染树只包含需要显示的元素和对应的样式信息。
4.布局计算:浏览器会根据渲染树的信息,计算出每个元素在页面中的位置和大小,这个过程称为布局计算(也叫回流)。
5.绘制:浏览器会遍历渲染树,根据每个元素的位置、大小和样式信息,将页面内容绘制到屏幕上。
6.栅格化:如果页面中有一些复杂的元素,比如使用了CSS3的变换或者动画,浏览器会将这些元素单独处理,生成位图,以提高性能。
7.合成和显示:浏览器会将绘制的内容进行合成,并将最终的图像显示在屏幕上。
浏览器使用流式布局模型 (Flow Based Layout)。
(图片来自网络)
三、回流和重绘是什么?
回流
,也叫重排,是指当 DOM 元素的几何属性(例如位置、大小)发生改变时,浏览器重新计算并更新元素的几何属性,并重新构建页面布局树的过程。回流会导致其他元素的几何属性和布局发生变化。回流是一种相对较慢的操作,会消耗大量的CPU资源。
重绘
是指当 DOM 元素的样式属性(例如颜色、背景)发生改变时,浏览器重新绘制元素的过程,但并不影响元素的几何属性和布局。相比于回流,重绘的性能开销较小。
回流一定会导致重绘,但是重绘不一定会导致回流
。回流相对较慢,会重新计算文档中元素的位置和几何属性。而重绘是根据元素的新样式重新绘制页面,不需要重新计算元素的位置和几何属性。
四、回流和重绘的性能影响
回流和重绘是比较昂贵的操作,它们会消耗大量的计算资源和时间。频繁的回流和重绘会导致页面性能下降,造成卡顿和延迟响应。
五、触发回流和重绘的情况
1. 触发重绘的情况
- 颜色属性:color、background-color、border-color等。
- 文字属性:font-weight、font-style、text-decoration等。
- 文本属性:text-align、text-transform、line-height等。
- 背景属性:background-image、background-position、background-size等。
- 盒子模型属性:box-shadow、outline-color、outline-style等。
- 渐变属性:linear-gradient、radial-gradient等。
- 变形属性:transform、transform-origin等。
- 过渡属性:transition、transition-property、transition-duration等。
上述操作只会触发重绘而不会引起回流。因为这些属性的修改只会影响元素的外观,而不会影响元素的布局。
2. 触发回流的情况
- 盒模型属性:width、height、padding、margin、border等。
- 定位属性:position、top、left、bottom、right等。
- 布局属性:display、float、clear、flex等。
- 字体属性:font-size、line-height、text-align等。
- 背景属性:background、background-color、background-image等。
- 盒子模型属性:box-sizing、border-box、outline等。
- 可见性属性:visibility、opacity等。
- 修改浏览器窗口大小。
- 页面初始加载。
- 页面的渲染树发生改变,如添加或删除元素等。
- 获取元素的一些布局属性,如offsetWidth、offsetHeight、clientWidth、clientHeight、getComputedStyle()、scrollIntoView()、scrollTo()、getBoundingClientRect()、scrollIntoViewIfNeeded()等。
当进行回流操作时,不仅会影响当前元素,还会影响该元素的子元素以及其他相关联的元素,因为它们的位置和尺寸也会受到影响而需要重新计算。
六、如何优化回流和重绘?
1. 使用CSS3动画
使用 CSS3 动画代替JavaScript动画(例如使用 transform 和 opacity 属性),可以利用 GPU 加速,减少回流和重绘的开销,性能更好。
2. 避免频繁访问布局信息
避免在 JavaScript 中频繁访问元素的布局信息(例如 offsetTop、offsetLeft、clientWidth、clientHeight 等),因为这会强制浏览器进行回流操作。
3. 批量修改样式
对需要修改样式的元素进行批量操作,将多个样式的修改合并为一次操作,避免频繁操作样式,减少回流和重绘的次数。
4. 使用transform属性
使用 transform 属性进行位移、缩放和旋转操作,因为它不会引起回流,只会触发重绘。
5. 使用文档片段
使用文档片段(DocumentFragment)进行DOM操作:将DOM操作放在文档片段中,最后一次性插入文档,减少回流次数。
6. 使用虚拟DOM
通过虚拟DOM的比较算法,最小化真实DOM的变动,减少回流和重绘的次数。
7. 其他
避免使用table布局,在DOM树的最末端改变class,避免设置多层内联样式。避免使用CSS表达式(例如:calc())。使元素脱离文档流。避免频繁读取会引发回流/重绘的属性等等。
8. 代码示例
// 优化回流和重绘的实践
const element = document.getElementById("myElement");
// 使用文档片段进行DOM操作
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement("div");
div.textContent = "Element " + i;
fragment.appendChild(div);
}
element.appendChild(fragment);
// 使用虚拟DOM进行DOM操作
const virtualDOM = [
{ id: 1, text: "Element 1" },
{ id: 2, text: "Element 2" },
// ...
];
function render() {
const container = document.getElementById("myContainer");
container.innerHTML = "";
virtualDOM.forEach((item) => {
const div = document.createElement("div");
div.textContent = item.text;
container.appendChild(div);
});
}
render();
// 使用CSS动画代替JavaScript动画
element.classList.add("animated");
减少回流和重绘的次数可以提升页面性能和用户体验。
七、最后的话
在JavaScript中,回流(Reflow)和重绘(Repaint)是两个性能优化方面非常重要的概念。了解这两个概念的含义和如何优化可以帮助我们编写更高效的代码,提升网页的性能。
能力一般,水平有限,本文可能存在纰漏或错误,如有问题欢迎大佬指正,感谢你阅读这篇文章,如果你觉得写得还行的话,不要忘记点赞、评论、收藏哦!祝生活愉快!
原文链接:https://juejin.cn/post/7248207744087769125 作者:牛哥说我不优雅