现在假设有个需求,要我们做三个方块,其中第三个方块要从初始位置往左滑动

先实现基础功能

我们先回顾一下简单的CSS动画是如何实现的:
image
此时的代码为:

<html>  
    <head></head>  
    <body>    
        <div id="a" class="area"></div>    
        <div id="b" class="area"></div>    
        <div id="c" class="area"></div>  
    </body>
</html>

<style>  
    .area {    
        width: 50px;    
        height: 50px;    
        margin-bottom: 10px;  
    }  
    #a {    
        background-color: red;  
    }  
    #b {    
        background-color: blue;
    }  
    #c {    
        background-color: green;    
        animation: slidein 5s infinite;  
    }  
    @keyframes slidein {    
        from {      
            margin-left: 0;    
        }    
        to {      
            margin-left: 100px;    
        }  
     }
 </style>

优化思路

我们通过改变margin的方式让第三个方块动了起来,好了工作完成了,该下班回家了。。。才怪,PM嫌咱们做的动画在老设备上太卡,要提高流畅度,我们该怎么优化咧?

在着手优化之前,我们得先想明白,为什么这种方式是低效的。我们都知道,浏览器渲染会进行重排和重绘,一旦文档结构发生变更,便会牵一发而动全身,导致元素布局重新计算,如果元素之间关联紧密且变动频繁,便容易出现卡顿。故而我们在进行CSS修改的时候,往往会刻意避免大量的结构变更,并且尽可能将多次CSS操作合并起来。

回到我们的动画上,动画元素天然就是不停在动的,浏览器也就不得不反复的进行着计算工作。那我们该怎么尽可能减少计算压力呢?很简单,让动的元素超脱出来,不干扰其他元素的布局即可。

用绝对定位可以不

我们脑子里一瞬间就闪出了万恶的绝对定位:

<style>  
    .area {    
        position: absolute;    
        left: 10px;    
        width: 50px;    
        height: 50px;  
    } 
    #a {    
        top: 10px;    
        background-color: red;  
    }  
    #b {    
        top: 65px;    
        background-color: blue;  
    }  
    #c {    
        top: 120px;    
        background-color: green;    
        animation: slidein 5s infinite;
    }  
    @keyframes slidein {    
        from {      
            left: 10px;    
        }    
        to {      
            left: 100px;    
        }  
    }
</style>

image

绝对定位的元素确实脱离文档流了,但它真能让动画元素超脱出来,减轻浏览器负担么,我们可以用Chrome的Layers视图来看一下:

(控制台 => more => More tools => Layers)
image.png

右侧的立体图只看截图不太直观,但左侧的图层我们可以看到只有文档一层,元素并没有成功完成"飞升",这种情况下浏览器的计算工作依然巨大,所以单纯的绝对定位等脱离文档流的方式,并不能满足我们的需求呢。

如果能让动的元素成为单独的一层,其他不动的当做背景层,才算真正脱钩呢,那该怎么实现呢?

让GUP上吧

我们把CSS动画实现的代码再来改版一下:

@keyframes slidein {    
    from {      
        transform: translateX(0);   
    }    
    to {      
        transform: translateX(100px);    
    }  
}

此时我们再来看一下Layers:
image.png

可以看到已经变成两层了呢,我们再换个角度截图:
image.png

可以看到绿色区域C已经完全脱离了原图层了呢,这是利用了CSS translate3d属性会使用GUP渲染的原理。

所以到目前为止我们终于可以得出一个有用的结论:动画元素尽可能用GUP渲染,最简单的是使用translate3d属性。

就这?

这种基础知识点确实没必要长篇大论说这么多,咱们接下来说说隐患。在我们的需求里,A和B元素都是不动的,只有最底层的C需要动起来,那么我们把需求改成让B动,C不用动了,图层的视角会怎么样咧?

<style>  
    .area {    
        position: absolute;    
        left: 10px;    
        width: 50px;    
        height: 50px;  
    }  
    #a {    
        top: 10px;    
        background-color: red;  
    }  
    #b {    
        top: 65px;    
        background-color: blue;    /* 只有B在动哦 */             animation: slidein 5s infinite;  
    }  
    #c {    
        top: 120px;    
        background-color: green;
    }  
    @keyframes slidein {    
        from {      
            transform: translateX(0);    
        }    
        to {      
            transform: translateX(0);    
        }  
    }
</style>

image.png

这貌似不对呀?只有B用GUP提升了,为啥会有三个图层,而且为啥看立体图C还在B上面?

这里涉及到一个知识点,在都不用GUP提升的时候,所有元素都在一个图层上,文档的上下排列顺序无所谓,不会出现谁在谁上面的问题。但一旦其中一个元素被GUP单独渲染,那么在它文档结构下面的、且脱离了文档流的元素,则也会被单独渲染为一个图层,文档结构越靠下图层层级便越高。

这样会带来什么问题呢?每个图层都将占用相应的内存,图层越多内存占用越多,随着而来的就是卡顿甚至崩溃。

那如何避免生成不想要的图层呢?也很简单,给动画元素加上z-index就可以了。

最佳实践

所以我们针对动画元素应该:

  1. 让该元素脱离文档流,比如position:relative;
  2. 让该元素用GUP渲染到独立图层,比如:transform: translateZ(0);
  3. 给该元素设置z-index: 1;

我们来看看让B动起来的最终代码:

<style>  
    .area {    
        width: 50px;    
        height: 50px;    
        margin-bottom: 10px;
    }  
    #a {    
        background-color: red;  
    }  
    #b {    
        position: relative;    
        z-index: 1;    
        background-color: blue;    
        animation: slidein 5s infinite;  
    }  
    #c {    
        background-color: green;  
    }  
    @keyframes slidein {    
        from {      
            transform: translateX(0);    
        }    
        to {      
            transform: translateX(100px);    
        }  
    }
</style>

以及对应图层视图:
image.png


魔芋药丸
15 声望0 粉丝