回到目录

[前端知识体系] 动画的实现

2017-04-16

本篇将涵盖网页动画几乎所有的实现方案并持续更新。同时以实际应用为目的,从实现成本(指开发者的实现)、文件体积、性能、表现力、交互性、兼容性(移动端与 PC 端)、使用场景等几个纬度进行评价。

在此提前给出一点普适技术层面的建议:考虑了硬件加速和页面性能之后,使用 CSS 几乎总是优于 JavaScript。有选择时,使用基于 CSS 的动画,将 JS 作为备选。

一、原生动画

如何定义原生动画?就是无需前端工程师通过代码实现即可直接在页面观看到的动画,一般由他人输出动画文件,前端工程师简单处理即可在页面浏览。这里姑且称之为「原生动画」。有以下几种:

  • GIF
  • Flash
  • Video
  • APNG
  • AWebP

1、GIF(动画恒久远,Gif 永流传)

GIF 在 1987 年被创造,比我的出生还早 4 年。更让人想不到的是,直到 30 年后的今天(2017),它依旧被广泛的使用着。虽然现在它越来越不够精细了,但大部分场景下依旧是动态图片最好的选择。

Gif 的优点有:

  • 浏览器原生支持,<img> 标签直接使用
  • 不用工程师编码实现,由设计师制作输出
  • 兼容性非常好,兼容所有移动和 PC 浏览器
  • 在合适的使用场景下(小 ICON),图片体积合适。

Gif 的缺点有:

  • 不管可不可见,浏览器都会一直渲染,性能一般
  • 只支持 256 种颜色,不支持半透明,边缘有毛刺
  • 没有交互能力,不能与用户互动,动画不可控制,不可暂停(没有借助其他库)
  • 一般的动图体积都上 M

Gif 的使用场景:

  • 适用于动画面积小,颜色数量少的场景,如连续播放的小 ICON 动画。
  • 目前社交平台中动图的主流实现方式,但现在逐渐减少。Twitter 的 App 开始用 .m4v 视频来播放动图;PC QQ 使用 APNG 的方式来播放动图。但至少微博目前还在用 Gif。

2、Flash(日渐式微,风光不在)

Flash 的诞生,追根溯源,在 1990 年代初期。2000 年前后,互联网已经开始普及,受限由当时的网络带宽,此时的互联网主要以文字为主,打开大一点的图片就要等上好一会时间,下载一首 MP3 可能就得等上三十分钟。而当时互联网上的动画表现形式,只有 GIF,使用浏览器观看视频还必须要安装 Media Player 插件或 Real Player 插件,在那网速只有 64K/128K/512K/1024K 的年代,Flash 大行其道起来,小小的几百 KB 至几 MB,支持流式播放,边下边播,在那个时候能在互联网上流畅播放的只有 Flash 了,不火才怪了。—— source

Flash 的优点:

  • 同样的效果其体积要小于 GIF 很多
  • 同样不需要工程师编码实现,由 Flash 设计师制作输出
  • 表现力不错(动画、广告、游戏),高清矢量,可以进行交互
  • 跨浏览器跨操作系统
  • 支持播放视频,支持流式播放
  • 交互能力较强,只能实现动画播放、暂停、进度调整、人为触发/控制/影响等

Flash 的缺点:

  • 性能差,需要大量计算资源,导致手机发热耗电,影响续航
  • 存在安全问题频出,对操作系统安全带来很大的隐患
  • 兼容性越来越差、目前主流移动浏览器不再支持

Flash 的使用场景:

  • 流媒体视频技术最初基于 Flash,常见各大视频网站。但逐渐被 HTML5 取代,不需要额外安装第三方插件
  • 通过 Flash 导出 HTML5 动画的方式可以做一些人工编码远远达不到的效率和效果,这算是 Flash 的另外一条出路

3、Video(突破想象,扩展 H5 表现力)

伴随着 HTML5 的发展,视频才逐渐得以在移动端大放异彩,以往网页中视频只能通过 Flash 播放器来播放,但现在一个 <video> 视频标签即可满足。原生支持的好处不仅仅在于免除插件的安装与升级,还有性能上的提升。这里有一个典型的案例,通过将视频插入到 H5 里,实现出乎意料的效果并带来了疯狂的传播 —— TGideas 出品的《吴亦凡即将参军》。

Video 的优点:

  • 不需要工程师编码实现,由制作视频的同事输出
  • 表现力绝佳,几乎没有视频无法呈现的效果
  • 可以边加载边播放,缓解文件大带来的问题

Video 的缺点:

  • 体积较大,弱网络环境影响页面效果
  • 由于存在解码过程,且视频分辨率普遍较高,比较耗性能
  • 交互能力比较弱,只能实现动画播放、暂停、进度调整等
  • <video> 标签虽然在移动端很早就被支持,但系统限制比较多,浏览器实现各异,坑很多
  • 放在页面中会把手机正在播放的音乐中断,这是个硬伤!
  • 移动网络下,部分安卓会默认不播放视频,或者弹窗提示是否播放视频,或者视频解析错误
  • 视频本身无法做到背景透明
  • 第三方浏览器实现各异,有些浏览器会禁用默认的视频标签,采用播放器来播放

Video 的适用场景:

  • 一般还是在 H5 中使用,主要用于创意类的品牌推广、产品传播、局部动画等。但在 PC 端被苹果运用的如火纯青,最经典的就是 Mac pro 的介绍页面。
  • 常见的应用场景还有视频背景,用于渲染氛围。

4、APNG(GIF 终结者)

APNG(Animated Portable Network Graphics)格式是 PNG 的位图动画扩展,但未获 PNG 组织官方认可。其扩展方法类似 GIF 89a,仍对原版 PNG 保持向下兼容。APNG 第 1 帧为标准 PNG 图像,剩余的动画和帧速等数据放在 PNG 扩展数据块,因此只支持原版 PNG 的软件会正确显示第 1 帧。

APNG 的优点:

  • 同 GIF 的制作模式,由设计师输出序列帧
  • iOS8 以上原生支持,性能和 GIF 类似
  • 表现力优于 GIF,支持 24 位真彩色,支持 8 位 Alpha 透明通道
  • 通过合理的压缩手段,体积会比 GIF 小 20~30% 左右

APNG 的缺点:

  • Android 浏览器并无原生支持,PC 端支持甚少
  • 如果动画帧数过多,文件体积还是蛮大的
  • 默认情况下不可交互,但经过改造可以实现交互能力,可暂停、播放、速率调整等

APNG 的使用场景:

  • 可以通过 apng-canvas JavaScript 库实现全平台兼容,经过改造的库还可以实现暂停、播放、进度调整等
  • 通过 JavaScript 轮播 PNG 序列帧,一般在 H5 中作为替代 GIF 的方案,承载复杂的动画。由于是 JS 轮播的,所以当页面 JS 执行较密集时,动画性能会被影响。

5、AWebP(Google 的玩物)

WebP 是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。根据 Google 的测试,无损压缩后的 WebP 比 PNG 文件少了 45% 的文件大小,即使这些 PNG 文件经过其他压缩工具压缩之后,WebP 还是可以减少 28% 的文件大小。想了解更多可以看我写的《WebP 探寻之路》

而 AWebP 就是 Animated WebP,其实跟 APNG 差不多,原理也是多张图片的轮播。但自我从 13 年研究过后,这个格式一直没有在其他浏览器支持上得到过更多的支持,也就是兼容性基本不变。iOS 就别想了,Android 使用起来倒是没有问题。另外一点就是,尽管官方宣称 AWebP 比 Gif 要小得多,提供的例子也验证了说法,但我自己通过工具转换后的图大部分都比 Gif 大。国外也有相关的测试证明了转换后 AWebP 不减反增,详见这里

这里就不对其进行优劣分析了,AWebP 的兼容性比 WebP 要更差,基本没有应用场景。

6、总结

通过一个表格来总结,分三种等级:好中差、高中低、强中弱、大中小。只有最差一等(红色)才意味着不可接受无法采用,中间一等意味着在可接受的范围内,最高一等(绿色)表示最佳选择。请注意这里的评价标准排序,越重要的排越前,若无法满足前面所列的标准,则一般意味着这种方式不可用。同是也把使用第三方插件带来的评判标准改善纳入考虑。

这里特别解释下部分评价标准的意思:

  • 兼容性:只看移动端(Android 和 iOS),不管 PC
  • 文件体积:在其适用场景下一般文件体积的大小
  • 实现成本:程序上的实现动画播放,而非动画的制作成本
  • 交互性:「弱」表示无法控制;「中」表示可暂停可播放可调整进度;「强」表示可完整控制动画所有状态
动画格式 兼容性 文件体积 性能优劣 实现成本 表现力 交互性
GIF 中 ✐
Flash
Video
APNG 中 ✐ 中 ✐
AWebP

注:✐ 表示借助其他方式(第三方库、工具)可以改善

二、CSS3 动画

在 CSS3 出现之前,CSS 本身并不具备动画能力(除非借助 JS),而 CSS3 的出现开启了网页动画新篇章,由于它被浏览器原生支持,并且可以通过硬件加速直接由 GPU 进行渲染,所以性能也非常好。这里介绍 CSS3 都能实现什么动画:

1、Transform(变换)

其实我更倾向于不给它一个中文翻译,因为只有英文 transform 才能表达它原生的意思。「变形金刚」的英文就是 Transformor,所以对于 transform 能做的东西,你是否有一点点感性的认识?接下来一个个介绍:

  • translate(位移):让网页元素从平面 (x1, y1) 点移动到 (x2, y2) 点
  • scale(缩放):让网页元素放大或缩小
  • rotate(旋转):让网页元素绕着某个点旋转
  • skew(倾斜):让网页元素发生倾斜变形
  • matrix(矩阵):把上面四种变换组合在一起

例如下面这段代码的意思是:把网页元素水平位移 10px,然后顺时针旋转 90°,再放大到 1.5 倍,最后水平倾斜 10°。

transform: translate(10px, 0) rotate(90deg) scale(1.5) skew(10deg, 0)

当然上面都是二维的动画,其实 CSS3 也具备伪三维的动画效果,即在原本 x/y 轴的基础上增加一个 z 轴(为何称之伪三维,因为它没有模型、场景、摄像头、渲染器等概念):

  • translate3d(位移):让网页元素从空间 (x1, y1, z1) 点移动到 (x2, y2, z2) 点
  • scale3d(缩放):让网页元素的长宽高放大或缩小
  • rotate3d(旋转):让网页元素绕着空间某点旋转
  • matrix3d(矩阵):同样是上面的组合

那 Transform 可以做什么动效?它基本可以涵盖页面大部分简单的动画了(要知道网页动效是相对简单的)。如页面转场动效、元素进出场动效、多种动画组合动效等等。

2、Animation(动画)

Animation 由一系列的 keyframe 组成,也就是我们常说的关键帧。它可以创建逐帧动画、路径动画、物理动画和组合动画。大家不妨看下面一段浅显易懂的代码:

@keyframes animation-name {
    0% {
        height: 0px;
        transform: translate(0, 0);
    }
    50% {
        height: 50px;
        transform: translate(10px, 10px);
    }
    100% {
        height: 100px;
        transform: translate(20px, 20px);
    }
}

概述上面这段动画,即:进度为 0% 的时候,网页元素的高度为0,不做变化;50% 的时候网页元素高度开始变换为 50px,水平和垂直位移到 (10px, 10px) 这个点;100% 的时候网页元素高度变换为 100px,水平和垂直位移到 (20px, 20px) 这个点。

@keyframes animation-name {
    0% {
        background-image: url(图片第一帧);
    }
    50% {
        background-image: url(图片第二帧);
    }
    100% {
        background-image: url(图片第三帧);
    }
}

如上所示,当我们把变换属性改成一帧帧图片的时候,就是所谓的逐帧动画了。

@keyframes animation-name {
    0% {
        transform: translate(0, -100px);
    }
    20% {
        transform: translate(20px, -70px);        
    }
    40% {
        transform: translate(30px, -50px);
    }
    60% {
        transform: translate(40px, -30px);    
    }
    80% {
        transform: translate(50px, -10px);            
    }
    90% {
        transform: translate(60px, 0px);
    }
    95% {
        transform: translate(65px, -5px);
    }
    100% {
        transform: translate(70px, 0px);
    }
}

如上所示,可以把运动拆解为水平和垂直方向的位移,动画效果类似抛物线扔出一个球,落地后反弹几次。也就是所谓的路径动画和物理动画了(代码比较拙劣,旨在表达意思,相信你也发现单纯通过人为编码的方式是写不出自然的物理动画的,还是需要工具来结合物理公式计算出关键帧动画)。

3、Transition(过渡)

transition 一般用于搭配 CSS 属性来做补间动画(也可以结合上面的 transform 属性),比如把一个正方形的宽从 100px 慢慢减少到 1px,这期间的动画就是 transition 来定义的。transiton 的语句一般这么写:

transition: width 1s ease 1s;

分别解释下参数的意义:

  • width:表示要做补间动画的属性(如 width 是宽度),只有支持动画的属性才能被 transition 使用,具体属性详见这里
  • 1s:表示过渡动画的时长,1s 表示一秒,1ms 表示一毫秒
  • ease:表示动画函数,ease 表示逐渐缓慢;linear 表示匀速;ease-in 表示加速;ease-out 表示减速,还支持 cubic-bezier 贝塞尔曲线
  • 1s:这个 1s 表示动画开始前延迟的时间

4、总结

CSS3 动画看似不多,但不同的属性组合起来实际上变化无穷,单纯是逐帧动画基本就能替代 Gif 和 APNG 了,而 transform、animation 可以做 Flash 能做的事情。

CSS3 动画的优点:

  • 随着 Android 2.3 的淘汰,CSS3 动画的兼容性基本能覆盖大部分机型
  • 动画代码量非常小,即使是 keyframe 代码也比一个动画文件小得多
  • 性能非常好,只要是 CSS3 写的动画,基本不需要考虑性能问题
  • 交互性极强,由于动画都是通过代码编写,可以任意控制(配合脚本语言)
  • 浏览器从底层优化动画序列,例如当 Tab 不可见的时候,降低更新的频率提高整体性能

CSS3 的缺点:

  • 实现成本中等,时间在可以接受范围内,基本不会影响整个项目进度
  • 表现力一般,由于都是简单变换组合而成的,自然没有如 Video 的表现力

CSS3 适用场景:

  • CSS3 适用于大部分网页动画场景,除了复杂的光影、粒子等特效、复杂的变形动画/路径运动、三维模型动画、骨骼动画等

 
排除掉上面基本淘汰的动画方案,加入 CSS3 之后,得到下面这份表格:

动画格式 兼容性 文件体积 性能优劣 实现成本 表现力 交互性
CSS3
GIF 中 ✐
Video
APNG 中 ✐ 中 ✐

注:✐ 表示借助其他方式(第三方库、工具)可以改善

三、CSS2 + JavaScript

上面说过,在 CSS3 出现之前,CSS 本身并不具备动画能力。需要结合 JavaScript 来制作动画,原理即通过脚本语言的定时器一帧一帧地控制 CSS 属性来产生动画。

哪些 CSS 属性支持动画呢(或者说动态改变)?可以在这里找到一份列表。

有一句话说得好:「动画是关于时间的函数」。CSS 属性我们都知道,比如 width、height、left、top,那 JavaScript 主要做什么呢?它的作用就是利用 setTimeout、setInterval 或 requestAnimationFrame 这几个定时器来不断循环一个函数,在这个函数里改变 CSS 属性值。其中定时器的频率也大有文章,可以将时间等分(即匀速动画),也可以将时间按照一定的数学公式来制造加速、减速、自由落体、反弹等效果。

我们经常会借助一些库来提升效率,常见的库有 GASPVelocityTween,当然由游览器原生提供的动画 API——Web Animation 也值得去学习,虽然现在几乎没有得到支持。

CSS2 + JavaScript 的优点:

  • 兼容性强,基本全支持
  • 文件体积跟 CSS3 都很小
  • 交互性极强,由于动画都是通过代码编写,可以任意控制

CSS2 + JavaScript 的缺点:

  • 由于通过 JavaScript 来控制动画,则有可能在 JavaScript 阻塞时动画也卡顿、丢帧
  • 实现成本相比 CSS3 要高一些,虽然不成问题,但大多数情况下可被 CSS3 取代

CSS2 + JavaScript 适用场景:

  • 基本上它和 CSS3 能做的事情是一样的,现在两者更多是融合一体的。唯一的差异是,通过 JavaScript 来控制动画,要比纯 CSS3 动画更加灵活可控,更能模拟自然运动,因为物理运动是可以通过公式来计算的,这比 CSS3 的贝塞尔曲线、关键帧动画更灵活。
  • 目前市面上一些 H5 喜欢通过 JavaScript 来逐帧播放视频导出的序列帧,这是一种规避视频问题的手法。它和 CSS3 Animation 做帧动画的区别在于:JavaScript 可以控制帧动画暂停与播放,还能改变速率等。

后面统一把 CSS2 和 CSS3 同成为 CSS。

动画格式 兼容性 文件体积 性能优劣 实现成本 表现力 交互性
CSS + JavaScript
GIF 中 ✐
Video
APNG 中 ✐ 中 ✐

注:✐ 表示借助其他方式(第三方库、工具)可以改善

四、Canvas 和 SVG

HTML 中一些标签可以用来承载动画,最典型的就是 Canvas 和 SVG 两种标签,但他们仅仅只是网页中的节点,动画内容是通过 JavaScript 来编写的。下面分别讲下这两种标签的能力:

1、Canvas

Canvas 可简单理解为画布,作为一张的画布,它可以被绘制任何内容,只有你想不到,没有它不能画的。Canvas 的优点有:

  • 兼容性强,所有移动端浏览器都支持
  • 文件体积小,都是代码编写
  • 表现力较强,可以做出很炫酷的效果
  • 交互性好,因为是脚本编写的动画
  • Canvas 只占用一个 DOM 节点,在做一些如烟花、飘雪等运动元素很多的动画时,它明显会比 CSS/SVG 性能更好

Canvas 的缺点有:

  • 纯脚本编写动画,实现成本较高
  • 涉及复杂运算的动画,Canvas 的性能不是很好,例如三维场景的渲染、粒子动效等

Canvas 的应用场景:

  • 数据可视化的基石之一,展示图表内容
  • 把视频绘制到画布中,可以规避 video 在移动端的一些坑
  • 通过对画布中的每个像素点进行加工处理,实现滤镜功能
  • 通过 WebRTC 对摄像头视频流进行处理实现 AR/图像识别/直播/聊天室等功能
  • 承载 WebGL 的渲染内容,将三维世界带到网页中

2、SVG

SVG 是一种图像格式,矢量不失真。用户可以直接用代码来描绘图像,可以用任何文字处理工具打开 SVG 图像,通过改变部分代码来使图像具有交互功能,并可以随时插入到HTML中通过浏览器来观看。

SVG 的优点:

  • 文件体积较小,纯代码编写
  • 矢量高清,缩放不失真
  • 交互性较好,可以通过交互实现动画执行与暂停

SVG 的缺点:

  • 兼容性一般,iOS 全支持,而 Android 3 以后开始支持
  • 不涉及非常多的节点的动画时,性能一般;节点多时,性能较差
  • 实现成本较高,除了脚本编写动画,还需要把设计师输出的路径导出
  • 表现力一般,因为其定位所有偏向,主要是基础点线面的矢量形变与移动动画

SVG 的适用场景:

  • 数据可视化的基石之二,展示高清图表内容
  • 取代 iconfont 作为新的图标实现方案
  • 定义路径制作非常自然的路径动画
  • 定义不同的形状,产生顺滑的形变动画

3、两者差异

Canvas 和 SVG 的差异(来自《H5动效的常见制作手法》):

  • Canvas 是画框,有自己固定的高宽,SVG 是不依赖分辨率的矢量图形
  • Canvas 能以 JPG/PNG 等格式保存图像,SVG 以文本格式来保存图像
  • Canvas 绘制的图像不占 DOM 节点,而 SVG 的每个图像都是 1 个 DOM 节点
  • Canvas 适合图像密集型的动画,而 SVG 不适合大量使用,例如制作飘雪等
  • Canvas 完全依赖脚本绘制作,而 SVG 可直接使用矢量转存生成

再来综合打分:

动画格式 兼容性 文件体积 性能优劣 实现成本 表现力 交互性
CSS + JavaScript
Canvas
GIF 中 ✐
Video
SVG
APNG 中 ✐ 中 ✐

注:✐ 表示借助其他方式(第三方库、工具)可以改善

五、WebGL

WebGL 是 Web 动画中最高阶的一部分。WebGL 基于 OpenGL ES 2.0,提供了 3D 图像的程序接口,也就是说 WebGL 是 OpenGL ES 2.0 的 Web 版封装,它使用 HTML5 Canvas 并允许利用文档对象模型接口。WebGL 相对于 HTML5 的关系就好比是 OpenGL 库和三维应用程序的关系。WebGL 只是提供了底层的渲染和计算的函数,而并没有定义一个高级的文件格式或交互函数。有一些开发者正在 WebGL 的基础上创建高级的程序库,比如在 Web3D 联盟推进下,浏览器可以解析 X3D-XML DOM 文档树中的三维内容,这样就可以直接在浏览器中浏览 X3D 格式的三维场景而不需要再安装额外的插件。

总结一下,即 WebGL 是一项利用 JavaScript API 渲染交互式 3D 电脑图形和 2D 图形的技术,可兼容任何的网页浏览器,无需加装插件。通过 WebGL 的技术,只需要编写网页代码即可实现 3D 图像的展示。

WebGL 的优点:

  • 相比其他方式实现同等效果,其体积会小非常多(但需引入一个较大的库)
  • 表现力非常好,基本可以跟 3D 软件媲美,单这个优势就抵过全部缺点了
  • 由于是代码实现,交互能力也很好

WebGL 的缺点:

  • 移动端兼容性已基本达到可用阶段,一些不可用的手机需降级处理
  • 由于涉及非常庞大的运算,移动端性能是个非常大的问题
  • 实现成本非常高,开发者还需具备其他领域的知识

WebGL 的适用场景:

  • 3D 模型制作与渲染:可以与模型进行交互(如拖拽、360度浏览、查看内部等)
  • 全景场景构建:如全景观看某个景点/房子内部,全景地图等
  • Web 虚拟现实:网页端的虚拟现实内容制作和技术实现
  • 3D 游戏制作:目前比较少,性能是个大问题

动画格式 兼容性 文件体积 性能优劣 实现成本 表现力 交互性
CSS + JavaScript
APNG 中 ✐ 中 ✐
Video
Canvas
SVG
WebGL
GIF 中 ✐

注:✐ 表示借助其他方式(第三方库、工具)可以改善

六、另辟蹊径

这一节讲的内容并没有脱离上述的实现方式,但动画的制作过程并非直接编码而成,而是通过第三方动画制作软件导出而成。好处即节省代码工作量,动画效果更接近设计师的制作,做出编码难以实现的效果。

1、Adobe CC

Flash 虽然在 Web 中逐渐走向没落,但它却以另外一种形式重新出现了前端开发者的视野中,多媒体设计师通过软件制作好了动画并交给前端工程师,如下图所示:

前端工程师可以针对源文件进行调整,甚至添加一些 JavaScript 交互代码

在调整完成后,选择发布为「JavaScript/HTML」,便可将相关资源导出到指定目录中,前端工程师经过一些操作 ,可以把包含了交互的动画在页面中展示出来:

最终在页面中可以看到动画成品,我们关注页面节点,可以发现其技术实现是通过 Canvas 而非 Flash:

2、After Effect

After Effect(简称 AE)是一款图形视频处理软件,适用于视频特技制作,影视后期处理等场景。但也可以制作在 App 或 Web 上展示的动画,这里需要借助一个插件叫做 Bodymovin,它可以将动画导出为一个 json 格式的文件,并通过脚本语言解析出动画:

成功导出后的文件通过 JavaScript 库即可在 HTML 中播放,注意它的底层实现是 SVG,我们在上面已经介绍过,SVG 适用的动画场景主要是路径、形变、变换等动画,所以它并不能导出光影或粒子效果。

3、Hype

Hype 是一款高效的动画原型制作工具,让设计师零代码只做出可以在 Web 中浏览的动画。它的优点即帮助设计师更好的将动画效果的关键信息传达给技术人员或用于演示和汇报,帮助非技术人员如市场运营或营销人员快速制作一些可线上传播的推广页面,操作简单支持响应式:

支持导出 HTML5 是它最核心的功能点,而且导出的动画效果还原度很高,底层实现原理是 CSS3 动画。

相关链接:

动画库: