重绘(Repaint)和回流(Reflow)

    科技2024-06-18  68

    重绘和回流会在我们设置节点样式时频繁出现,同时也会很大程度上影响性能。

      1、重绘是当节点需要更改外观而不会影响布局的,比如改变 color 就叫称为重绘。

      2、回流是布局或者几何属性需要改变就称为回流。

    回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变父节点里的子节点很可能会导致父节点的一系列回流。

    以下几个动作可能会导致性能问题:

      1、改变window大小

      2、改变字体

      3、添加或删除样式

      4、文字改变

      5、定位或浮动

      6、盒模型

    并且很多人不知道的是,重绘和回流其实也和Eventloop有关

      1、当Eventloop执行完Microtasks后,会判断document是否需要更新,因为浏览器时60Hz的刷新率,每16.6ms才会更新一次。

      2、然后判断是否有 resize 或者 scroll 事件,有的话会去触发事件,所以 resize 和 scroll 事件也是至少 16ms 才会触发一次,并且自带节流功能。

      3、判断是否触发了 media query。

      4、更新动画并且发送事件。

      5、判断是否有全屏操作事件。

      6、执行 requestAnimationFrame 回调。

      7、执行 IntersectionObserver 回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好。

      8、更新界面。

      9、以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行 requestIdleCallback 回调。

    以上内容来自HTML文档

    既然我们已经知道了重绘和回流会影响性能,接下来介绍如何减少重绘和回流的次数。

    减少重绘和回流

      1、使用transfrom替代top。

      

    <div class="test"></div> <style> .test { position: absolute; top: 10px; width: 100px; height: 100px; background: red; } </style> <script> setTimeout(() => { // 引起回流 document.querySelector('.test').style.top = '100px' }, 1000) </script>

      2、使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)。

      3、不要把节点的属性值放在一个循环里当成循环里的变量。

      

    for(let i = 0; i < 1000; i++) { // 获取 offsetTop 会导致回流,因为需要去获取正确的值 console.log(document.querySelector('.test').style.offsetTop) }

      4、不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。

      5、动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame。

      6、CSS 选择符从右往左匹配查找,避免节点层级过多。

      7、将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于 video 标签来说,浏览器会自动将该节点变为图层。

      8、设置节点为图层的方式有很多,我们可以通过以下几个常用属性可以生成新图层

    will-change

    video、iframe 标签

    提示如何加速

    从文件大小考虑

    从 script 标签使用上来考虑

    从 CSS、HTML 的代码书写上来考虑

    从需要下载的内容是否需要在首屏使用上来考虑

    小结

    我们了解了浏览器如何将文件渲染为页面,同时也掌握了一些优化的小技巧。

    Processed: 0.021, SQL: 8