CSS动画并非绝对比JavaScript动画性能更优越,开源动画库Velocity.js等就展示了强劲的性能。javascript
先开门见山的说说二者之间的区别。css
1)CSS动画:html
基于CSS的动画通常由浏览器“主线程”以外的独立线程处理,在其中执行样式、布局、绘制和 JavaScript。前端
使用CSS动画,容许对单个动画关键帧、持续时间和迭代进行更多控制。html5
但缺少表现力,而且很难有意义地组织动画,这意味着创造动画会带来较高的复杂度和错误率。java
2)JavaScript动画:css3
在浏览器主线程的JavaScript中运行,主线程已经忙于运行其余的JavaScript,样式的计算,布局还有绘制。线程内存在资源竞争,这实质上增长了掉帧的风险。git
基于JavaScript的动画灵活性更高,彻底控制元素在每一个步骤,能更好的实现复杂的动画和大量的交互(例如当要求全部的元素在页面加载时顺次加载显示出来)github
对于多元素多步骤的动画序列、交互拖拽动画等,用JavaScript实现则是上选。web
1)步骤
为了能让动画高性能的执行,得先了解一下页面渲染。
页面渲染的通常过程为JavaScript > 计算样式 > 布局 > 绘制 > 渲染层合并。
Layout:计算每一个DOM元素最终在屏幕上显示的大小和位置。页面中一个元素的布局发生变化,会联动地引起其余元素的布局发生变化。
Paint:绘制文字、颜色、边框和阴影等,也就是一个DOM元素全部的可视效果。这个绘制过程可能会在多个层上完成的。
Composite:在每一个层上完成绘制以后,浏览器会将全部层按照合理的顺序合并成一个图层,而后显示在屏幕上。
2)优化
Layout(重排)和Paint(重绘)是整个环节中最为耗时的两环,因此咱们尽可能避免着这两个环节。
为了实现上述效果,就须要只使用那些仅触发Composite的属性。
能够选择transform和opacity,animate.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:黄褐色就是合成层,青色的细线是浏览器渲染时候的“瓦片”,浏览器绘制页面的时候只会绘制可视区域必定范围内的瓦片,以节省性能开销。
1)CSS动画事件
CSS动画有两种方式设置Transition过渡和Animation。
与过渡相关事件只有一个TransitionEnd,也就是在过渡结束后触发。
与animation相关事件有三个,animationstart、animationiteration与animationend。
两个动做相关的事件比较少,因此控制动画很是有限制,应对复杂场景蛮吃力的。
2)requestAnimationFrame
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。
参考资料: