如何实现动画?
- jQuery animation:setTimeout,top/left
- animatin,transition,transform
- javascript+canvas/webGL/SVG
- requestAnimationFrame
- GPU acceleration(硬件加速)
webkit的渲染流程
css style影响
浏览器渲染小结
- 渲染三个阶段: Layout,Paint,Composite Layers
- 修改不同CSS属性会触发不同阶段
- 触发的阶段越前,渲染的代价越高
硬件加速(GPU加速)
- Texture,即GPU传输到GPU的一个Bitmap
- GPU能快速对texture进行偏移、缩放、旋转、修改透明度等操作
- 相同之处:两者都有总线和外界联系,有自己缓存体系,以及数字和逻辑运算单元。一句话,两者都为了完成计算任务而设计。
- 不同之处:CPU主要负责操作系统和应用程序,GPU主要负责跟显示相关的数据处理,GPU的活CPU一般都可以干,但是效率低下
Layer模型
- 浏览器根据CSS属性为元素生成Layers
- 将Layers作为texture上传到GPU
- 当改变Layer的transform,opacity属性时,渲染会跳过Layout,paint,直接通知GPU对Layer做变换。
Layer创建标准
- 拥有3d transform属性
- 使用animation,transition实现opacity,transform的动画
- video
- canvas
- Flash
- 使用CSS filters的元素
- z-index大于某个相邻节点的Layer的元素
为什么使用硬件加速快呢?
- 如果使用jquery或者js来做一个top移动100px的动画,每次都会重主线程发传到合成器线程
- 但是,如果用GPU transform来做的话,主线程只会传一次到合成器线程,其余任务全部是在合成器线程,所以效率比较高。
节省了哪些时间?
- CPU进行Layout和paint的时间
- CPU向GPU传输位图的时间
完美的Animation
对眼睛来说:60FPS更舒服更完美
约等于16.7ms内,我们准备好一帧的动画
- 开始绘制的时间
- 绘制一帧的时间
- setTimeout(callback,1/60)
依靠浏览器内置时钟更新频率,eg、IE8及以前更新间隔为15.6,setTimeout 16.7,它需要两个15.6ms触发。超过14.5ms,所以会出现丢帧的现象
main thread队列 - requestAnimationFrame
- 定义绘制每一帧的工作requestAnimationFrame(callback)
- 自动调节频率 ,callback工作太多无法再一帧内完成,会自动降低为30fps,虽然频率降低但比丢帧好。
Layout
触发Layout
- 改变widht,height等和大小、位置相关的属性
-
读取size、positoin相关的属性
尽量不触发Layout,使用transform代替top,left的动画。
但是,如果是这样
我们可以这样改
介绍一个库
fastdom.js
在每一帧,先将读操作批量运行,在批量运行写操作
Layout小结
- 不但改变css可能导致Layout,读取位置大小相关属性也会导致Layout(滚动条也会导致Layout)
- 分离读写,减少Layout
- 面对解耦代码,可以使用rAF推迟的方法分离读写
如何开发不会导致重拍
- 样式表越简单,重拍和重汇越快
- 重拍和重绘的DOM元素层级越高,成本就越高
- table元素的重排和重绘成本,要高于div元素
- 尽量不要把读操作和写操作,放在一个语句里
- 统一改变样式
- 缓存重排结果
- 离线DOM Fragment/clone
- 虚拟DOM React
- 必要的时候display:none不可见元素不影响重排重绘。visibility对重排影响不影响重绘
Paint
触发paint
- 当修改border-radius,box-shadow,color等展示相关属性,会触发paint
paint的代价
- continuous painting mode
- paint prefiler
- 在经常paint的区域,要避免代价太高的style(比如不要的gif图设置display:none)
减少不必的绘制
- gif图即使被其他Layout盖住不可见,也可能导致paint,不需要时应将gif图的display属性设为none。轮播图也一样 http://jsbin.com/dizak/3/edit?html,css,output (可以用调试工具去测试性能,z-index:0,也会重排重绘,应该直接设置display:none)
- 减少绘制区域,为引起大范围Paint的元素生成独立的Layout以减小Paint的范围
Paint小结
- 简化绘制的复杂度
- 避免不必要的绘制
- 减少绘制区域
composite Layout
- GPU也是有限度的,不要滥用GPU资源生成不必要的Layout
- 留意以外生成的Layout