MST
星途 面试题库

面试题:CSS性能优化之重排与重绘

请详细阐述CSS属性变化导致重排(reflow)和重绘(repaint)的原理。列举一些会频繁触发重排或重绘的CSS操作,并说明如何优化以减少对性能的影响。
13.4万 热度难度
前端开发CSS

知识考点

AI 面试

面试题答案

一键面试

重排(reflow)和重绘(repaint)原理

  1. 重排(reflow)原理
    • 重排也叫回流,当页面布局和几何属性(例如元素的尺寸、位置、隐藏/显示等)发生变化时,浏览器需要重新计算元素的几何属性,进而重新构建渲染树,这个过程就是重排。
    • 浏览器渲染页面时,首先会构建文档对象模型(DOM)和CSS对象模型(CSSOM),然后将两者结合生成渲染树(render tree)。渲染树包含了页面中所有可见元素及其样式信息。重排发生时,渲染树的部分或全部会被重新计算和构建。例如,当改变元素的宽度,浏览器需要重新计算该元素及其子元素的位置和尺寸,可能还会影响到其他相邻元素的布局,导致整个渲染树部分甚至全部重新布局。
  2. 重绘(repaint)原理
    • 重绘是当元素的外观(例如颜色、背景色、边框样式等)发生变化,但不影响布局时,浏览器需要重新绘制受影响的部分,这个过程就是重绘。
    • 重绘只涉及更新元素的外观,而不需要重新计算布局。例如,改变元素的颜色,浏览器只需在渲染树中找到该元素对应的节点,然后重新绘制其外观,而不会影响其他元素的布局。

频繁触发重排或重绘的CSS操作

  1. 频繁触发重排的操作
    • 改变元素的尺寸:例如修改widthheightpaddingmarginborder-width等属性。当这些属性改变时,元素的几何尺寸发生变化,会导致浏览器重新计算布局,触发重排。
    • 改变元素的位置:如修改topleftbottomright(对于定位元素),transform属性的translate部分(虽然transform在一些情况下有性能优化,但改变translate值仍会触发重排),这些操作改变了元素在页面中的位置,浏览器需要重新布局。
    • 改变元素的字体大小:字体大小的改变会影响文本的布局,进而影响整个元素及其周围元素的布局,触发重排。
    • 添加或删除可见的DOM元素:添加新元素会改变文档的结构,可能影响其他元素的布局;删除元素同样可能使周围元素重新排列,从而触发重排。
  2. 频繁触发重绘的操作
    • 改变元素的颜色:例如修改colorbackground - color等属性,元素的外观颜色改变,浏览器需要重新绘制该元素,触发重绘。
    • 改变元素的边框样式:如修改border - styleborder - color等,元素的边框外观变化,导致重绘。
    • 改变元素的透明度:修改opacity属性,元素的透明度发生变化,需要重新绘制以显示新的透明度效果,触发重绘。

优化以减少对性能的影响

  1. 批量操作
    • 尽量一次性修改元素的多个属性,而不是逐行修改。例如,不要多次分别修改widthheightmargin,可以使用CSS类,一次性应用多个样式。
    <style>
      .new - style {
         width: 200px;
         height: 100px;
         margin: 10px;
       }
    </style>
    <div id="myDiv"></div>
    <script>
      const div = document.getElementById('myDiv');
      // 不好的方式,多次触发重排
      div.style.width = '200px';
      div.style.height = '100px';
      div.style.margin = '10px';
      // 好的方式,只触发一次重排
      div.classList.add('new - style');
    </script>
    
  2. 使用requestAnimationFrame
    • 当需要进行动画或连续的DOM操作时,使用requestAnimationFrame。它会在浏览器下一次重绘之前调用指定的回调函数,这样可以将多次操作合并到一次重排/重绘中。
    function updateElement() {
      const div = document.getElementById('myDiv');
      div.style.width = '300px';
      div.style.height = '150px';
    }
    requestAnimationFrame(updateElement);
    
  3. 将元素脱离文档流
    • 在进行大量布局改变操作前,将元素设置为position: absoluteposition: fixed,使其脱离文档流,这样对该元素的操作不会影响其他元素的布局,从而减少重排范围。操作完成后再恢复其原来的定位。
    <style>
      .myDiv {
         position: relative;
       }
    </style>
    <div id="myDiv" class="myDiv"></div>
    <script>
      const div = document.getElementById('myDiv');
      // 脱离文档流
      div.style.position = 'absolute';
      // 进行大量布局操作
      div.style.width = '400px';
      div.style.height = '200px';
      // 恢复原来定位
      div.style.position ='relative';
    </script>
    
  4. 使用will - change属性
    • 在提前知道元素属性会发生变化时,使用will - change属性告知浏览器提前做好优化准备。例如,如果知道一个元素的transform属性即将改变,可以提前设置will - change: transform。但要注意不要滥用,因为它可能会占用额外的内存。
    #myDiv {
      will - change: transform;
    }