本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力。
这里的高效,我觉得包括两方面:分别是编码的高效和性能的高效。
- 编码的高效 作为前端开发,我们在给低版本浏览器做动画时,会特别的痛苦,因为需要用js去实现。无论多简单的动画,都需要写js去控制整个过程。比如有个id为box的dom元素,需要加个鼠标hover效果,hover时其匀速向右移动100px,需要编写以下的js代码去实现:
var dom = document.getElementById('box');
var y = 0;
var timeid = setInterval(function(){
dom.style.left = (y++) + 'px';
if (y >= 100) {
clearInterval(timeid);
}
}, 16);
这仅仅只是最简单的动画效果,如果页面存在多个动画,且动画之间有时序要求,那实现就更复杂了,代码里会嵌套大量的setTimeout来控制时序,这样会导致代码难以维护和调试。 幸运的是,业内给我们提供了不少的库来解决这个痛点,如Velocity、jQuery等等。
但这些库的本质还是通过js去实现动画的,那有没有不需要js就能实现的动画呢,有的,那就是css3动画,但其不支持低版本的浏览器(ie9以下),实现动画只需要编写css。在不考虑浏览器兼容的情况下,我们来看看同样实现上面的动画效果,需要编写哪些代码:
#box {
/* 其他样式代码 */
position: absolute;
transition: transform linear 1s;
}
#box:hover {
transform: translateX(100px);
}
是不是比上面的js清爽很多呢,关键transition: left linear 1s;
这句,用来设置元素的过渡效果。没这句的话,hover时box会瞬间右移100px,无动画效果。是不是比使用js实现简单高效的多呢。实际开发中,动画远远复杂得多,除了transition属性,css还提供了更精细的keyframes帧动画,具体用法留给大家去探索。总的来,css动画比js的简洁清晰,易于维护。
- 性能的高效 css动画的另一个高效是表现在性能上。除去网络请求,影响页面性能的主要是浏览器的重排和重绘。比如在前端开发的常识里,有一条就是减少dom节点的操作,因为这可能会引起页面的重排或重绘。改变dom元素的内容、位置、尺寸大小等几何属性,导致浏览器不得不重新计算元素的几何属性,并重新构建渲染树,这个过程称为“重排”;完成重排后,要将重新构建的渲染树渲染到屏幕上,这个过程就是“重绘”。改变个元素的背景,这个就不涉及元素的几何属性,所以只发生重绘。
像上面代码的dom.style.left
,每改变一次元素的位置,都会触发一次重排和重绘,不停的在改变元素位置时,页面的布局也不断的在变化,就会造成浏览器耗费大量的开销在进行页面的计算,从而导致页面卡顿。而且js是运行在浏览器主线程里的,当通过setTimeout、setInterval定时器实现动画时,可能会短时间内导致事件队列里积压大量的任务,使得页面暂时的假死。
那么css动画会有这样的问题吗,是没有的。因为css动画是运行在合成线程里的,所以不会阻塞主线程。二期能直接在合成线程中完成的任务都不会改变dom元素的内容、位置的改变,颜色的改变,所以就不会触发重排或者重绘了。合成线程流程大致分两步:分层和合成。为了提高渲染效率,分层会把页面元素分层,类似于Photoshop的图层,将页面分为多个图层的操作称为分层,然后将这些图层合成一起的操作称为合成。
因为将页面分了不同的层,当对元素进行css动画时,如平移、旋转、缩放等操作,只需对相应的层进行操作,然后合成线程再把图层合并在一起就可以了。
总的来说,重排、重绘比较耗时耗性能,而css动画由合成线程渲染的,而合成操作是在渲染进程的合成线程上执行的,执行速度快,且不占用主线程,所以更加高效。