为什么要避免大量的重绘和重排

重排是指元素的位置、尺寸等几何属性发生变化,需要重新计算页面布局的过程。在某些情况下,如窗口大小改变、DOM元素的增删改等,都可能导致重排。重排会重新计算整个页面的布局,因此性能影响较大。
重绘是指元素的几何属性不变,页面的外观发生变化,重新绘制,但不影响布局的情况,例如改变元素的颜色、背景色等。重绘不会带来重新计算布局的开销,因此性能影响相对较小。但是,如果重绘操作频繁发生,也会对性能产生影响。

当我们改变一个尺寸位置属性时,会重新进行样式计算,布局,绘制,以及后面的所有流程。这种行为我们称为重排。当我们改变某个元素的颜色属性时,不会重新触发布局,但还是触发会样式计算和绘制,这个就是重绘。我们可以发现重排和重绘会占用主线程,JS的运行也是在主线程。既然他们都是在主线程就会出现抢占执行时间的问题。
如果我们写了个不断导致重绘重排的动画,浏览器则需要在每一帧都会运行样式计算、布局和绘制的操作,我们知道当页面以每秒大于60帧的刷新率,才不会让用户感觉到页面卡顿。
在这里插入图片描述

如果在运行动画时,还有大量的js任务需要执行,因为布局绘制和js的执行都是在主线程运行的,当在一帧的时间内,布局和绘制结束后,还有剩余时间,js就会拿到主线程的使用权,如果js执行时间过长就会导致在下一帧开始时,js没有及时归还主线程,导致下一帧动画没有按时渲染,就会出现页面动画的卡顿。
在这里插入图片描述
那有什么优化的手段吗?

有,第一种就是可以通过requestAnimationFrame()这个api来帮助我们解决这个问题。requestAnimationFrame这个方法会在每一帧被调用,通过这个api的回调参数,可以把JS运行任务分成一些更小的任务块(分到每一帧),在每一帧时间用完前暂停JS执行归还主线程,在下一帧开始时主线程就可以按时执行布局和绘制。
在这里插入图片描述

还有第二个优化方法。我们知道栅格化整个流程是不占用主线程的,只在合成器和栅格线程中运行,这就意味着它无需和js抢夺的主线程。刚才提到,如果我们反复重绘和重排,可能会导致掉帧,因为有可能会有js的执行阻塞了主线程。css中有个动画属性叫transform,通过该属性实现的动画,不会经过布局和绘制,而是直接运行在合成器线程和栅格线程中,所以不会受到主线程中js执行的影响。更重要的是transform的动画,由于不需要经过布局绘制样式计算,所以节省了很多运算时间。可以让复杂的动画更加流畅。我们常常通过位置变化、宽高变化来实现动画效果,这些都可以使用transform来代替(transform:translate(x,y)、transform:scale(x,y)、transform:rotate(deg))。

避免重排reflow
reflow 的本质就是重新计算 layout 树。
尽量减少对DOM的操作,特别是那些会引起布局变化的操作。可以通过以下方法来避免:
将多个对DOM的修改合并在一起,使用文档片段(document fragment)或先在非显示状态下进行批量更新,然后一次性应用到DOM上。

let fragment = document.createDocumentFragment(); 
for (let i = 0;i<10;i++){ 
let node = document.createElement("p"); 
node.innerHTML = i; 
fragment.appendChild(node); 
}
document.body.appendChild(fragment); 

使用局部变量缓存DOM元素的几何属性,如宽度、高度等,减少对样式的重复访问。
将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。
不要经常获取同一个元素,可以第一次获取元素后,用变量保存下来,减少遍历时间。
尽量少使用dispaly:none,可以使用visibility:hidden代替,dispaly:none会造成重排,visibility:hidden会造成重绘。
不要使用Table布局,因为一个小小的操作,可能就会造成整个表格的重排或重绘。
使用resize事件时,做防抖和节流处理。
如果要批量添加DOM,可以先让元素脱离文档流,操作完后再带入文档流,这样只会触发一次重排。

避免重绘repaint
repaint 的本质就是重新根据分层信息计算了绘制指令。
使用CSS的transformopacity属性进行动画,这些变化会创建新的图层,不会触发重绘。
通过requestAnimationFrame来控制动画,可以确保动画在合适的时间高效执行。
将元素提升为合成层,合成层的位图,会交由 GPU 合成,⽐ CPU 处理要快。提升合成层的最好⽅式是使⽤ CSS 的 will-change 属性:

#target { 
will-change: transform; 
}

参考链接:
https://mp.weixin.qq.com/s/_phLApBXsuOun0KeSoIPlQ
https://blog.csdn.net/Poggie/article/details/136487985
https://zhuanlan.zhihu.com/p/503647367

  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
重绘重排是CSS渲染过程中的两个重要概念。 重绘(Repaint)指的是当元素的样式发生变化,但不影响其布局时,浏览器会将新样式应用到元素上,重新绘制元素的外观。重绘的开销相对较小,不会引起布局的变化。 而重排(Reflow)指的是当页面布局发生变化时,例如修改了元素的尺寸、位置、内容等,浏览器会重新计算并更新元素的几何属性(如大小、位置),然后重新布局页面。重排的开销相对较大,因为它涉及到整个页面或部分页面的重新渲染。 重绘重排的区别在于是否引起布局的变化。重绘只会重新绘制元素的外观,而不会影响其周围元素的布局;而重排会导致整个渲染树的重新构建和布局。 在性能优化方面,我们通常要尽量减少重排重绘的次数,因为它们会消耗大量的计算资源。一些常见的优化方法包括: 1. 使用 CSS3 动画或过渡代替 JavaScript 实现的动画效果,因为后者可能会导致频繁的重排重绘; 2. 使用类似 flexbox 和 grid 等布局技术,可以减少页面布局的复杂性,降低重排重绘的次数; 3. 避免频繁访问会引起重排重绘的属性,例如 offsetTop、offsetLeft、scrollTop、clientWidth 等; 4. 批量更新样式或布局,可以使用 CSS 类名的方式一次性修改多个元素的样式,而不是逐个修改; 5. 将需要执行多次重排的 DOM 操作尽量合并为一次,使用文档片段(DocumentFragment)进行缓存。 通过合理优化和减少重排重绘的次数,可以提升页面的性能和响应速度。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值