前端逐帧动画性能探究和比较

什么是逐帧动画?

首先看一下维基百科中的定义:

定格动画,又名逐帧动画,是一种动画技术,其原理即将每帧不同的图像连续播放,从而产生动画效果。

简单的来说就是:

以一定的速度切换几张连续图像,让它动起来。

 

人眼的物理性能能识别多少帧?

理论上说,帧率越高,动画会越流畅,目前大多数设备的屏幕刷新率为 60 次/秒,所以通常来讲帧率为 60 帧时动画效果最好,也就是每帧的消耗时间为 16.67ms。

 

直观感受,不同帧率的体验:

  • 帧率能够达到 50 ~ 60 FPS 的动画将会相当流畅,让人倍感舒适;
  • 帧率在 30 ~ 50 FPS 之间的动画,因各人敏感程度不同,舒适度因人而异;
  • 帧率在 30 FPS 以下的动画,让人感觉到明显的卡顿和不适感;
  • 帧率波动很大的动画,亦会使人感觉到卡顿。

 

【同屏帧数对比】24/30/50/60帧:https://www.bilibili.com/video/av19011575/

前端方案有哪些?

直接使用动态图像

GIF

GIF是一种位图,最高支持256种颜色。由于这种特性,GIF比较适用于色彩较少的图片,比如页面Loading图、卡通造型、公司标志等等。

 

(圣诞节时保存下来的一张GIF图像)

 

GIF 优缺点

优点:实现小细节动画,成本较低、使用方便、兼容性好。

 

缺点:

画质上,GIF 支持颜色少(最大256色)、Alpha 透明度支持差,图像锯齿毛边比较严重;

交互上,不能直接控制播放、暂停、播放次数,灵活性差;

大小上,GIF 的每帧都要完整地存下来,而且是无损压缩,文件太大

性能上,GIF 会引起页面周期性的绘制 ,性能较差。

为什么 GIF 格式迟迟没有被取代?

原因有以下几点:

几乎所有的主流浏览器都支持GIF(GIF-1987);

实现起来简单,制作工具多;

APNG/WEBP格式是怎么回事?

我们先来了解一下图像的有损和无损压缩区别

有损压缩——你看到的不一定是真实的

我的理解是有损压缩是在存储图像的时候并不完全真实的记录图像上每个像素点的数据信息,它会根据人眼观察现实世界的特性(人眼对光线的敏感度比对颜色的敏感度要高,生物实验证明当颜色缺失时人脑会利用与附近最接近的颜色来自动填补缺失的颜色)

我们对图像数据进行处理,去掉那些图像上会被人眼忽略的细节,然后使用附近的颜色通过渐变或其他形式进行填充。这样既能大大降低图像信息的数据量,又不会影响图像的还原效果。

 

 JPG是我们最常见的采用有损压缩对图像信息进行处理的图片格式。JPG在存储图像时会把图像分解成8*8像素的栅格,然后对每个栅格的数据进行压缩处理,当我们放大一幅图像的时候,就会发现这些8*8像素栅格中很多细节信息被去除,而通过一些特殊算法用附近的颜色进行填充。这也是为什么我们用JPG存储图像有时会产生块状模糊的原因。

无损压缩——最精确的拼图

 相对有损压缩而言无损压缩则会真实的记录图像上每个像素点的数据信息,但为了压缩图像文件的大小会采取一些特殊的算法。无损压缩的压缩原理是先判断图像上哪些区域的颜色是相同的,哪些是不同的,然后把这些相同的数据信息进行压缩记录,(例如一片蓝色的天空之需要记录起点和终点的位置就可以了),而把不同的数据另外保存(例如天空上的白云和渐变等数据)。

APNG格式

APNG是PNG的升级版,他的后缀名依然是.png,包含动态的情况下体积会比普通静态png大数倍,可以无损的展示动态,但是他目前还没有得到PNG组织官方认可。

APNG的优势,各种动图制作工具,优化工具都有相应的项目来支持。而且在iOS上的WebView里面是除GIF外,唯一官方支持的动图格式,因此如果IOS开发需要WebView引入动图,APNG还是可以考虑一下的。

兼容性:https://caniuse.com/#feat=apng

                         前端逐帧动画性能探究和比较_第1张图片

WEBP格式

2010年谷歌推出的图片格式WEBP,专门用来在web中使用,压缩率只有jpg的2/3或者更低,第一个版本的webp图片格式是有损的,新版本中webp图片是无损的。相对于png图片,webp比png小了45%,但是缺点是你压缩的时候需要的时间更久了;

Android基本上对APNG可以说是没有什么支持的,所以如果是移动开发两个平台兼顾,建议同时准备APNG(for iOS WebView)和Animated WebP,客户端上建议是用Animated WebP,因为VP8的解码速度相对于APNG有一些优势。

兼容性:https://caniuse.com/#feat=webp&search=WebP

前端逐帧动画性能探究和比较_第2张图片

其他格式

TPG、BPG、FLIF

TPG图片加速架构

Web 支持的场景:在微信和手Q 场景传播的 H5 业务及小程序已支持。

Native 支持的场景:集成 TPG 解码 SDK。

如何看待腾讯推出宣称性能优于谷歌 webp 的新图片格式 TPG?

                         前端逐帧动画性能探究和比较_第3张图片

BPG了解一下

BPG 是目前已知最优秀的有损压缩格式了,它能在相同质量下比 JPEG 减少 50% 的体积。BPG 的解码速度还是差 JPEG 太多,大约慢了 3~5 倍。目前来说,BPG 适用于那些对流量非常敏感,但对解码时间不敏感的地方。

BPG会像JPEG一样被广泛使用吗?

答案是未必,各大公司做的算法有好有差,算法差的公司很有可能拿好的公司的算法用,然后做产品卖,然后被发现,打官司要求禁用该算法在该公司产品的使用。连JPEG这么老的协议都有很多公司在为自己拥有这个专利而争执不休,BPG要打破大公司之间的壁垒,而被广泛使用,其实还存在诸多变数。

FLIF大法好

自由无损图像格式Free Lossless Image Format,缩写 FLIF)是一个 无损图像格式,(当前版本FLIF16规范)声称对各种输入的压缩比优于 PNG、无损 WebP、无损 BPG和无损 JPEG 2000。

开发者称FLIF支持渐进交错,下载一小部分无损压缩图像文件后能解码出效果不错的完整有损图像

在照片上,PNG表现不佳,而WebP,BPG和JPEG 2000的压缩效果很好

                         前端逐帧动画性能探究和比较_第4张图片

在医学图像上,PNG和WebP的性能相对较差

                         前端逐帧动画性能探究和比较_第5张图片

在地理地图上,BPG和JPEG 2000的性能(极差),而PNG和WebP的效果很好

                         前端逐帧动画性能探究和比较_第6张图片

然而(逼王登场)在这三个示例中,FLIF都表现出色,甚至比其他任何一个都好。

JS帧动画

JS动画的原理是通过setTimeout、 setInterval 或requestAnimationFrame 方法绘制动画帧,从而动态地改变网页中图形的显示属性(如DOM样式,canvas位图数据,SVG对象属性等),进而达到动画的目的。

使用 setTimeout 或 setInterval 来执行动画之类的视觉变化,但这种做法的问题是,回调将在帧中的某个时点运行,可能刚好在末尾,而这可能经常会使我们丢失帧,导致卡顿。

                         前端逐帧动画性能探究和比较_第7张图片

保证 JavaScript 在帧开始时运行的方式是使用 requestAnimationFrame。

什么是渲染帧?

这得从显示器的刷新频率说起,目前的LCD液晶显示器,刷新频率规格大多在60Hz。

60Hz什么概念呢,就是大约每16.66毫秒刷新一次屏幕,叫做一个渲染帧。

你现在看到的屏幕,就是用这种高速在不断的做一次又一次的渲染。

在这个渲染帧到下个渲染帧期间,加上JS线程和GUI线程之间的通信等损耗,你的代码尽量在10ms左右完成才能保证不掉帧。

说一说Lottie

Lottie 是Airbnb开源的一个动画框架,它提供了一套完整的跨平台动画实现流程,对IOS、Android、Web三端提供支持,如下图所示,主要通过AE上的Bodymovin插件将制作好的动画导出成一个json文件,json文件中记录了每个元素的动画执行路径和执行时间,最后交由Lottie解析和渲染。

使用Lottie方案有以下不足之处:

  • lottie-web文件本身仍然比较大,lottie.js大小为513k,轻量版压缩后也有144k,经过gzip后,大小为39k。所以,需要注意lottie-web的加载。目前H5项目有离线包,PWA,会对其进行缓存,保证加载速度。
  • lottie动画其实可以理解为svg动画/canvas动画,不能给已存在的html添加动画效果;
  • 动画json文件的导出,目前是将AE里面的参数一一导出成json内容,如果设计师建了很多的图层,可能仍然有json文件比较大(20kb)的问题,所以需要设计师遵循一定的规范。
  • 有少量的AE动画效果,lottie无法实现,有些是因为性能问题,有些是没有做。比如:描边动画等。

号称高性能动画播放体验的SVGA

SVGA 是YY的一种跨平台的开源动画格式,同时兼容 iOS / Android / Web。SVGA 实质上会在动画播放前,一次性地上传所有纹理到 GPU,接着在播放的过程中,这些纹理会被重复使用。CPU 与 GPU 交换的次数大大减少,同时,纹理的数目也在可控范围。

SVGA 不足之处:

这个格式还是只支持最最基础简单的动画效果,复杂一点的就歇菜了。

 

CSS3动画

CSS3动画的原理是通过​@keyframes/animation​定义元素在动画中的关键帧,以实现渐变式的过渡。

CSS3 硬件加速

CSS3 硬件加速又叫做 GPU 加速,是利用 GPU 进行渲染,减少 CPU 操作的一种优化方案。

因为重排和重绘发生在动画的每一帧,一个有效避免reflow和repaint的方式是我们仅仅画两个图像;一个是a元素,一个是b元素及整个页面;我们将这两张图片发送给GPU,然后动画发生的时候;只做两张图片相对对方的平移。也就是说,仅仅合成缓存的图片将会很快;这也是GPU的优势——它能非常快地以亚像素精度地合成图片,并给动画带来平滑的曲线。

动画图解

渲染层小实验:

                         前端逐帧动画性能探究和比较_第8张图片





  

    

    层级问题测试

    

  

  

    
     
通过transform 3d调起GPU的div,会重新建一个层(下方新开渲染层的情况都是叠加在一起的时候出现,详情修改top属性值,查看博客 https://blog.csdn.net/cmyh100)
     
普通层的div
     
加了zindex的div也在普通层
     
加了relative的div在普通层
     
加了relative与zindex小于新层的div在普通层
     
加了relative与zindex大于等于新层的div会被默认认为是调起了GPU渲染
     
加了absolute的div在普通层
     
加了absolute与zindex小于新层的div在普通层
     
加了absolute与zindex大于等于新层的div会被默认认为是调起了GPU渲染
     
opacity属性在animation变化的时候也会新开一层
   
   

能触发硬件加速的属性

  1. transform
  1. opacity
  1. filter
  1. Will-change

内存占用

使用GPU动画需要发送多张渲染层的图像给GPU,GPU也需要缓存它们以便于后续动画的使用。

一个渲染层,需要多少内存占用?为了便于理解,举一个简单的例子;一个宽、高都是300px的纯色图像需要多少内存?

300*300*4 = 360000字节,即360kb。这里乘以4是因为,每个像素需要四个字节计算机内存来描述。

假设我们做一个轮播图组件,轮播图有10张图片;为了实现图片间平滑过渡的交互;为每个图像添加了will-change:transform。这将提升图像为复合层800*600*4*10 = 1920000,它将多需要19mb的空间。

硬件加速的坑

Element has a sibling with a lower z-index which has a compositing layer (in other words the it’s rendered on top of a composited layer)

如果有一个元素,它的兄弟元素在复合层中渲染,而这个兄弟元素的z-index比较小,那么这个元素(不管是不是应用了硬件加速样式)也会被放到复合层中。

浏览器有可能给复合层之后的所有相对或绝对定位的元素都创建一个复合层来渲染。

优化技巧

使用3D硬件加速提升动画性能时,最好给元素增加一个z-index属性,人为干扰复合层的排序,可以有效减少chrome创建不必要的复合层,提升渲染性能,移动端优化效果尤为明显。

ps:

字节跳动 - 今日头条深圳PGC团队内推

招聘岗位:前端开发工程师

岗位详情:https://job.toutiao.com/s/bYPfAU

有意向的小伙伴可以通过链接投递简历或者直接私信我

你可能感兴趣的:(优化与兼容)