重排是否一定会引起会重绘

207 阅读2分钟

重排、重绘

提及这两个概念很多老哥第一反应肯定是:重排必然会引起重绘,但重绘不会引起重排,因为网上大多数资料都是这么说的。

重排真的一定会引起重绘么?首先先来看几个概念

重排

dom节点几何属性/位置等发生变化时,需要重新进行样式计算,然后生成布局树,重新计算位置信息/大小

重绘

dom节点的颜色属性/透明度绘制属性发生变化,需要重新绘制

页面渲染流水线

页面第一次加载时,整个渲染过程大致如下

image.png

浏览器渲染流水线.png

可以看出正常情况下,页面渲染过程先经历重排,然后再重绘。

只重排不重绘

如下动画

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            width: 100%;
            margin: 0;
            padding: 0;
        }

        .box {
            width: 100%;
            height: 200px;
            border: 1px solid red;
            position: relative;
            box-sizing: border-box;
        }

        .child {
            background: hotpink;
            width: 50px;
            height: 50px;
            animation: play 16ms infinite;

            /* 开启硬件加速 */
            transform: translate3d(0,0,0); 

        }


        @keyframes play {
            0% {
                left: 0;
            }

            100% {
                left: 400px
            }
        }
    </style>
</head>

<body>
    <div class="box">
        <div class="child">child</div>
    </div>
    <div class="box">
        <div class="child">child</div>
    </div>
    <div class="box">
        <div class="child">child</div>
    </div>
    <div class="box">
        <div class="child">child</div>
    </div>
</body>

</html>

使用transform属性让浏览器为参与动画的节点child分别创建单独的合成层合成层作为纹理上传存储在GPU中,当通过css修改child节点的几何属时,会进行: 样式计算->重排(loyout)->从GPU取出缓存的纹理(位图),不用重绘 -> 图层合成 -> 合成图片展示

image.png

重排然后重绘

上面的动画去掉transform: translate3d(0,0,0);后,child没有了单独的合成层,没有了缓存,所以每一帧都需要重新绘制

image.png

结论

  1. 可见重排不一定就会重绘两者没有必然的因果联系

  2. 常说的硬件加速之所以提升动画性能,是因为创建了单独的合成层,可以将合成层的纹理缓存在GPU中,动画播放时,只需读取纹理在合成线程进行图层的合成,避免重排、重绘占频繁占用渲染主线程导致的卡顿

    将动画由left改成translateX后:

     ```html
             @keyframes play {
                 0% {
                     transform: translateX(0);
                 }
    
                 100% {
                     transform: translateX(400px);
                 }
             }
     ```
    

    动画播放过程只有图层的合成,主线程完全空闲

    image.png