梅须逊雪三分白,雪却输梅一段香——CSS动画与JavaScript动画
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
CSS动画并不是绝对比JavaScript动画性能更优越开源动画库Velocity.js等就展现了强劲的性能。
一、两者的主要区别
先开门见山的说说两者之间的区别。
1CSS动画
基于CSS的动画一般由浏览器“主线程”之外的独立线程处理在其中执行样式、布局、绘制和 JavaScript。
使用CSS动画允许对单个动画关键帧、持续时间和迭代进行更多控制。
但缺乏表现力并且很难有意义地组织动画这意味着创造动画会带来较高的复杂度和错误率。
2JavaScript动画
在浏览器主线程的JavaScript中运行主线程已经忙于运行其他的JavaScript样式的计算布局还有绘制。线程内存在资源竞争这实质上增加了掉帧的风险。
基于JavaScript的动画灵活性更高完全控制元素在每个步骤能更好的实现复杂的动画和大量的交互例如当要求所有的元素在页面加载时顺次加载显示出来
对于多元素多步骤的动画序列、交互拖拽动画等用JavaScript实现则是上选。
二、页面渲染
1步骤
为了能让动画高性能的执行得先了解一下页面渲染。
页面渲染的一般过程为JavaScript > 计算样式 > 布局 > 绘制 > 渲染层合并。
Layout计算每个DOM元素最终在屏幕上显示的大小和位置。页面中一个元素的布局发生变化会联动地引发其他元素的布局发生变化。
Paint绘制文字、颜色、边框和阴影等也就是一个DOM元素所有的可视效果。这个绘制过程可能会在多个层上完成的。
Composite在每个层上完成绘制之后浏览器会将所有层按照合理的顺序合并成一个图层然后显示在屏幕上。
2优化
Layout(重排)和Paint(重绘)是整个环节中最为耗时的两环所以我们尽量避免着这两个环节。
为了实现上述效果就需要只使用那些仅触发Composite的属性。
可以选择transform和opacityanimate.css中很多的动画都是用这两个属性实现的。
从Css Triggers的网页中可以看到两个属性的描述
多层绘制方式的好处是使用tranform来实现移动效果的元素将会被正常绘制同时不会触发对其他元素的绘制。
《H5动画60fps之路》中通过一张图总结了一些针对性的优化方法
优化方法中提到了一个属性will-change可以将元素提升为合成层不过兼容性不太友好。
对于不支持此属性的可以使用一个3D transform属性来强制浏览器创建一个新的渲染层也就是人们常说的硬件加速。
.css{
transform: translate3d(0,0,0);
}
过一个大转盘抽奖的项目当使用“transform:rotate(0deg)”没有创建一个新的渲染层那么就会在不停的重绘高亮的地方就是重绘。
当改用“transform:rotate3d(0,0,1,0deg)”新增一个渲染层后只会重绘一次在电脑上看不出性能区别在手机上就会非常明显卡的不能动。
3工具
在Chrome浏览器中有工具可以查看到重绘与合成层。
Paint Flashing就是看重绘重绘的地方会高亮。
Layer Borders黄褐色就是合成层青色的细线是浏览器渲染时候的“瓦片”浏览器绘制页面的时候只会绘制可视区域一定范围内的瓦片以节省性能开销。
三、动画相关事件
1CSS动画事件
CSS动画有两种方式设置Transition过渡和Animation。
与过渡相关事件只有一个TransitionEnd也就是在过渡结束后触发。
与animation相关事件有三个animationstart、animationiteration与animationend。
两个动作相关的事件比较少所以控制动画非常有限制应对复杂场景蛮吃力的。
2requestAnimationFrame
requestAnimationFrame函数就是针对动画效果的API与显示器固定的刷新频率保持同步利用这个刷新频率进行页面重绘一般来说这个频率为每秒60帧。
此外一旦页面不处于浏览器的当前标签就会自动停止刷新这就节省了CPU、GPU和电力。
这个函数是在主线程上完成如果主线程非常繁忙那么动画效果会降低。
我们常用的setInterval、setTimeout是开发者主动要求浏览器去绘制因为动画不会与屏幕的刷新率同步很可能出现抖动和跳帧。
各个浏览器对此函数的支持程度不一样可能需要添加前缀也可能需要Polyfill一下。
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
上面的代码按照1秒钟60次大约每16.7毫秒一次来模拟requestAnimationFrame。
参考资料