欢迎移步我的博客阅读:《实用的 CSS — 动画性能对比》
前言
在现代浏览器中,渲染页面所要负责的线程主要有两个:主线程和排版线程。
主线程
运行 JS
计算 HTML 元素的 CSS 样式
布局页面
把页面元素绘制成一个或多个位图
把这些位图移交给排版线程
在浏览器开始渲染页面,或者长时间执行某个 JS 时,主线程会一直在忙碌状态,此时对于用户的任何输入或是操作都不会有所响应。
排版线程
通过 GPU 渲染位图,并显示在屏幕上
向主线程请求更新位图的可见部分或即将可见的部分
判断出当前页面处于可见的部分
判断出即将通过页面滚动而可见的部分
随着用户滚动页面来移动这些部分
排版线程对于用户的操作保持快速的响应,普遍的效率时每秒 60 帧的速度去刷新显示。
Transtion
下面我们在网页中实现一个元素的高度变化的动画,鼠标悬浮在元素上动画启动,直至完成:
<style>
#foo {
height: 100px;
width: 100px;
background: red;
transition: height 1s linear;
}
#foo:hover {
height: 200px;
}
</style>
<body>
<div id="foo"></div>
</body>
通过对上述代码的观察,让我们来了解一下浏览器的两个线程是如何协同工作的:
图中橘黄色部分代表操作相对较慢,消耗较大;蓝色部分代表操作相对较快,消耗较小
从上图我们可以看到,浏览器的两个线程在来回地切换工作,而且橘黄色出现次数较多,这意味着浏览器需要处理相当多的工作。
对于浏览器而言,由于元素的高度一直在变化,因此这个动画的每一帧中,都需要重新布局 ——> 绘制页面 ——> 将新的位图加载到 GPU 中 ——> 显示。而其中加载到 GPU
是一个相对缓慢的操作。
同时我们也在通过浏览器去查看元素动画的过程,其实是由略微卡顿的现象的。
Transform
经过上面的实验,我们对 transition
属性有了比较好的了解;同时我们对上述动画性能也有一个了解。接着我需要在网页中实现一个元素的大小变化动画,鼠标悬浮在元素上动画启动,直至完成:
<style>
#bar {
height: 100px;
width: 100px;
background: red;
transition: transform 1s linear;
}
#bar:hover {
transform: scale(2);
}
</style>
<body>
<div id="bar"></div>
</body>
完成上述实验,再让我们来看看两个线程工作的过程:
由此我们可以看到,两个线程来回切换的情况并不多,橘黄色部分出现的次数也较少,蓝色部分居绝大部分,这意味着这个动画效果相较于上面的要流畅很多。
在定义中,transform
是不会使浏览器产生重新排版的,因此 transform
不会影响原本的布局,以及周围的元素。它会将定义的元素作为一个整体进行缩放、移动或旋转等。
基于 transform
这类的特性,浏览器在渲染页面时可以节省很多不必要的开支,例如重新布局和将位图传给 GPU 等工作,这样就使得动画更有效率。
总结
当页面需要位移动画时,我们有两种方案:使用 position
或是 transalte
,而这两种是符合上述情况的。其中 position
的位移方案与第一个符合,在动画执行过程中会使浏览器重新渲染;另一外 transalte
则与第二个符合,在执行动画时不会发生重新渲染。因此,在需要写动画时,我们需要选择合适的方案,最好是选择 scale()
、rotate()
、transalte()
等,因为他们具有更好的性能。
参考
W3C: CSS Transforms
W3C: CSS Transitions
css-animations-and-transitions-performance
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。