美文网首页
浏览器渲染回流重绘与性能优化

浏览器渲染回流重绘与性能优化

作者: hui树 | 来源:发表于2020-02-12 17:26 被阅读0次

我们根据渲染的流程可知, 回流一定会触发重绘,而重绘不一定会回流。

渲染性能优化

回流和重绘的代价是比较昂贵的,渲染性能优化,就是要尽可能减少Layout回流和Paint重绘发生的次数,将回流和重绘的影响范围限制在单独的图层之内

1、合并多次布局操作

我们可以合并多次对DOM和样式的修改,然后一次处理掉,以此来最小化回流和重绘操作,比如:

// bad

const el = document.getElementById('test');

el.style.margin = '5px';

el.style.width = '100px';

el.style.borderRight = '2px';

例子中,有三个样式属性被修改了,每一个都会影响元素的几何结构,引起回流。(当然,大部分现代浏览器都对其做了优化,只会触发一次。但是如果在旧版的浏览器或者在上面代码执行的时候,有其他代码访问了布局信息,那么就会导致三次回流)

我们合并所有的布局操作,然后统一处理,比如这样:

// good

const el = document.getElementById('test');

el.style.cssText += 'margin: 5px;width: 100px;border-right: 2px; '

2、减少或避免强制同步布局

上面我们提到,访问一些属性(就是 offsetWidth 那一堆属性)会导致浏览器强制清空队列,进行强制同步布局。实际使用中可以尽量避免,如果不能避免,也应该减少。

比如我们想批量将一些标签的宽度设为某个box的宽度,我们可能会写成下面这样:

// bad

  for (let i = 0; i < elment.length; i++) {

        elment[i].style.width = box.offsetWidth + 'px';

    }

这段代码看上去问题不大,但是在每次循环的时候,都会去读取box的 offsetWidth ,导致浏览器每次都会因强制同步布局而触发回流,造成了很大的性能问题。

类似这这情况,我们可以把读取到的 offsetWidth 进行缓存:

// good

const width = box.offsetWidth;

for (let i = 0; i < element.length; i++) {

    element[i].style.width = width + 'px';

}

3、使用 transform 和 opacity 来实现动画

最佳的性能渲染流程,就是直接避开回流和重绘,只运行 Composite 合成这一操作。

目前可以有合成器单独处理的属性有两个:

transforms 和  opacity

比如我们可以使用 translate 代替 left 、 top 。

使用 opacity 代替 visibility 等

4、简化绘制的复杂度、减小绘制区域

除 transform 或 opacity 属性之外,更改任何属性始终都会触发绘制。

绘制通常是像素管道中开销最大的部分;应尽可能避免绘制。

4.1 通过层的提升来减少绘制区域

绘制并非总是绘制到内存中的单个图像。事实上,在必要时浏览器可以绘制到多个图像或合成器层,各个层可以在彼此的上面处理并合成,以创建最终图像。

创建新层的最佳方式是使用 will-change CSS 属性。

此方法在 Chrome、Opera 和 Firefox 上有效,并且通过  transform 的值将创建一个新的合成器层:

.moving-element {

    will-change: transform;

}

对于不支持 will-change 但受益于层创建的浏览器,例如 Safari 和 Mobile Safari,需要开启GPU加速来强制创建一个新层:

.moving-element {

    transform: translateZ(0);

}

4.2 优化或减少动画编排

减少绘制区域往往是编排您的动画和变换,使其不过多重叠,或设法减少动画编排,避免对页面的某些部分设置动画。

4.3 降低绘制的复杂性

一些css属性的绘制比其他绘制的开销更大。例如,绘制任何涉及模糊(例如 shadow )的元素所花的时间将比绘制一个 border 的时间要长。

实际开发中,我们要确定可否使用一组开销更小的样式,或者替代方式来实现最终结果。

5、让复杂的布局“离线”

对于复杂的动画,或者频繁触发回流的元素,我们

创建一个 documentFragment 或 div ,在它上面应用所有DOM操作,最后再把它添加到 window.document 。

也可以在一个 display:none 的元素上进行操作,最终把它显示出来。因为 display:none 上的DOM操作不会引发回流和重绘。

也可以使用绝对定位,让它脱离文档流,从而避免引起父元素以及后续元素的频繁回流。

6、其他

6.1 避免使用table布局

我们已经在上面说过, <table> 的计算需要不止一次的遍历,table是可以影响之前已经进入的DOM元素的显示的元素。即使一些小的变化和会导致table中所有其他节点回流。

相关文章

网友评论

      本文标题:浏览器渲染回流重绘与性能优化

      本文链接:https://www.haomeiwen.com/subject/qyucfhtx.html