从手机端 H5 制作来看 WEB 动画的术与道

3,743 阅读13分钟

我们在微信朋友圈里经常看到很多人分享 H5 的链接,有的科技感十足,有的展示炫目,有的非常有创意,各大公司也把H5作为他们品牌传播,活动预热的很好方式。企业商户对于这种方式也很有好感,从而导致了 H5 制作行业涌进大批从业者。这几年做过几十个 H5 ,每一次都在思考动画与技术的关系,于是记录下来。

H5

当你拿到一个 H5 制作的需求的时候,你需要首先明确需求的目的是什么?按照目的大概可以分为活动营销,产品宣传,会议邀请,品牌推广,企业招聘等。不同类别的 H5 有其自身的特点,但找准业务方的目的,就能抓住主题而不会跑题了。 接下来就是围绕这个主题思考创意。创意很多是来自于营销策略,方法以及对于人性的把握,这些偏软性的思考方式,我们先不讨论,作为一个程序员,我首先想到的就是怎么通过技术带来创意。

在此之前,我们先来看看制作一款 H5 有哪些「术」。

一个需求只要处在疯狂的爆炸成长期,行业看到了其巨大的市场,就一定会尽量的降低成本和使用门槛,来尽快的吸引用户,于是一些低门槛的h5制作平台相继出现,不懂代码的人也可以来玩玩,如果你有一定的设计思维和作图能力,也能做出非常好看的H5作品了。综合我的使用经验,大概总结如下:

国内比较成熟的 H5 制作平台有:

  • 兔展:设计感和创意感最强的平台,但是制作相对复杂,需要设计基础。
  • 易企秀:老牌的 H5 制作平台,不断迭代,有大量案例,使用别人做好的 H5 需要付费。生态圈还不错。
  • 初页:手机 APP,手机端快速制作 H5 。适合个人用户快速制作。
  • Epub360 意派:面向设计师,提供了很多创意的设计元素和案例。

易企秀 H5 制作后台

这些平台都可以让用户通过简单的拖拽来制作一个精美的 H5 ,这种打包预设好一些动画模式的方式,非常像我们前端开发中的组件化思维,他们将元素和数据分离,用数据模型来描述元素的位置和运动,同时开发出一套动画引擎,只要将模型数据输入,就能呈现出精美的动画。

我觉得这些平台非常合适的 WEB 动画的学习,深入探究其动画的实现思路,可以让我们快速的梳理出「动画」和「 WEB 动画技术」。

WEB 动画技术

你在做动画的时候,真的理解是什么是动画吗?维基百科告诉我们,动画是由一帧帧的静态图片按照一定的顺序,一定的速度播放而产生的,是一种障眼法。然而我并不想这么生硬的去理解他,对于真实世界的观察或许能给我们更为真切的体感。我们想一想人在运动的时候,我们肢体动作包含哪些动画元素呢?

简单动画

  • 移动 (水平,垂直)
  • 旋转
  • 缩放 (放大,缩小)
  • 样式属性

身体的位移,骨骼的旋转,瞳孔的缩放,这些都是最基本的运动方式,样式的变化,则是元素自身属性的变化,例如颜色,边框,背景等,这写也是大部分动画编程最基本的要素。你完全可以使用 CSS3 来实现他。我们知道一个动画要包含,元素变化。CSS3 基于 DOM 元素,借助动画三剑客 Transition (过渡) Transform(变形) Translate (移动),实现变化。有一个非常好用的 CSS 动画库 —— Animate.css ,他预设了很多实用的动画模版,你只要在 DOM 节点上添加响应的 class 就可以了。

他们即简单又复杂,复杂在于这些运动的方式和速度、时间的结合诞生出了速度曲线,然而大自然中大多数的速度曲线来自于重力加速度 G ,由于他的存在,物体的运动不像真空中那种匀速直线的单调乏味。而充满了生机。

尤其是当你在做动画的时候,为什么你做出的动画显得非常的生硬,让人看着不舒服,其实人早已习惯了大自然的动画方式,人对每一帧动画都有稳定的预期,当你的动画与现实物体的运动脱节,就会变得生硬。

基于上述简单动画催生了一种人体动画的形式---叫做「骨骼动画」。

复杂动画

骨骼动画的制作,属于一种相对复杂的动画形式,我们通过代码一点一点的写会非常困难,幸运的是业界早就有了成熟的工具帮助你省去了复杂的编码过程,让你只去关注创作本身。有两款比较著名的 2D 骨骼动画制作软件:Spine 和 DragonBones 。

DragonBones 骨骼动画软件操作界面

我们以 DragonBones 为例,我们发现下面的有一部分,操作栏是「时间轴」,他可以描述我们每一帧动画的状态,这里其实出现了两种与时间相关的动画形式。

  • 逐帧动画
  • 关键帧动画

作为一个前端工程师,我们在做动画的时候往往不会去写每一帧的动画的状态,而是先去定义起始状态和中间动画的过渡方式,例如速度如何变化,路径如何变化。这是一种关键帧动画,在 CSS3 中我们可以用 Animation 中的Keyframes 来实现关键帧动画,Keyframes 来定义关键帧的状态,Animation 来定义时间和速度变化。

而对于逐帧动画,则明显不是 CSS3 的强项,这里就要引出更为强大的武器 —— Canvas 了。

逐帧动画

在 Canvas 中,动画的元素可以由 Canvas 面板自定义的形状绘制,也可以加载图片来实现。元素的变化,则依赖 requestAnimationFrame(callback) 函数,推进时间的流逝,来重绘每一帧的画面。在逐帧动画领域有一个比较著名的框架,PixiJS 。

PixiJS 一直以高性能的 2D 渲染引擎著称。Pixi 主要负责渲染画面。可以创建丰富的交互式图形,动画和游戏,而无需深入了解 WebGL API 或处理浏览器和设备兼容性的问题。与此同时,PixiJS 具有完整的 WebGL 支持,如果需要,可以无缝地回退到 HTML5 的 Canvas 。PixiJS 默认使用 WebGL 渲染,也可以通过声明指定 Canvas 渲染,WebGL 在移动端 Android 4.4 browser 并不支持,不过可以使用 Canvas 优雅降级。

进入 Pixi 的世界,我们欣喜若狂,终于可以实现像素级别的动画了,Pixi 提供的强大滤镜,也让我们实现很多特效变得非常简单,然而作为一个渲染引擎,他很好的做到了高性能,而忽略了易用性,学习成本比较高,API比较复杂,尤其是逐帧动画的编码方式似乎有点反常识,或者说写起来并不是那么顺畅,而关键帧动画似乎更符合我们的编程习惯,毕竟 CSS 动画,我们烂熟于心。

那怎么用 Canvas 实现关键帧动画呢?我们为了实现某种目的,首先应该找的是方法,而方法往往已经被前人总结好,放在了你的面前,这里我们来聊两个框架: CreateJSGreenSock

关键帧动画

当我们定义了关键帧和变化方式以后,算法会帮我们计算出元素在每一帧的状态,我们把这称之为补间动画。 CreateJS 和 GreenSock 都是实现补间动画的高手。

CreateJS 和 GreenSock 都是基于 HTML5 的一套模块化的库和工具。不仅可以实现 Canvas 动画,也支持 DOM 动画,DOM动画的原理依然是基于 CSS3 的,由于 CSS 动画三剑客并不会引起浏览器页面内容的重排和重绘,甚至还可以开启 GPU 加速,性能比直接操作 DOM 的 width、left、margin 等属性要高的多。

其实 CSS 动画和 Canvas 动画的性能到底哪个更好,并不能一概而论,这个依赖于你具体使用的场景和浏览器类型,具体的性能比较可以看 这里 ,而我认为促使我们选择 Canvas 来做动画的一个关键点在于两者明显不同的思考方式。

  • 我们把动画的主体叫做元素,在 DOM 上,元素是按照经典的「盒子模型」做组装和布局的,盒子模型天然具有父子关系和相对位置。当我们实现一些局部动画的时候,是非常方便的。
  • Canvas 并没有盒子的概念,他只有一个画布标签,而这张画布被称为舞台,舞台上任何的元素都可以自由的运动,这更像真实世界的运作方式。
  • 这两种思考方式可能正是UI设计师和前端工程师,在工作时的差异。当我们用前端的「盒子」思维开发一个拖拽式页面工具让设计师来用的时候,你就天然的在要求他们用自己不熟悉的方式去思考,画画和设计他们只有一张画板,他们先打上均匀的格子,然后找准方位,一气呵成,他们在意的是整理的美观性。

话说回来,我们来看看,关键帧动画基本的实现形式是怎样的?CreateJS 中有一个专门实现关键帧动画的库——TweenJS,而 GreenSock 中也有同样功能的库—— TimelineMax。

// TweenJS 的 API
createjs.Tween.get(circle, { loop: true })
  .to({ x: 400 }, 1000, createjs.Ease.getPowInOut(4))
  .to({ alpha: 0, y: 175 }, 500, createjs.Ease.getPowInOut(2))
  .to({ alpha: 0, y: 225 }, 100)
  .to({ alpha: 1, y: 200 }, 500, createjs.Ease.getPowInOut(2))
  .to({ x: 100 }, 800, createjs.Ease.getPowInOut(2));

// TimelineMax 的 API
var tl = new TimelineMax();
tl.to(element, 1, {left:100}).to(element, 1, {top:50}).to(element, 1, {opacity:0});

我们可以看到,两者 API 非常的相似,都采用了链式调用的方式,定义每一个关键帧和时间,以及非常关键的运动曲线,区别在于 TweenJS 专注单个元素的运动,TimelineMax 更关注在一个时间线上,不同元素的运动。

相比而言,对于动画的实现上,GreenSock 借鉴了很多 Flash 的实现方式,插件非常多,功能更全,效果更炫。其实当我们在选择一门动画框架的时候,切记不要贪多,在满足需求的基础上,深入去研究一种框架,达到熟练,才能做出更好的效果和创意。我一直认为,创新是建立在丰富的知识储备和见识之上的自然涌现,尤其要求对技术的深度,如果一直在尝试不同的框架,就只能不停的学习各种 API ,而忘记了动画的本质并不是技术,而是好的创意。

当我们在实现动画的时候,慢慢会发现,大部分的元素都是图片,而且图片是提前预设好的,不能更改,只能用新的图片替换,例如当我们要实现微笑动画的时候,需要画两张图,一幅是闭着嘴的,一幅是张嘴笑的,然后逐帧播放。这样的画面当你有足够多帧图片的时候,并不会看出生硬,一旦低于 24 帧就是变得不自然了,那怎么在不增加工作量的前提下,实现流畅的变化呢?我们将关键帧动画的思维嫁接到元素自身扭曲变化上,就催生出了「柔性动画」的概念。

柔性动画

从上图可以看出,元素之间是可以相互变化的,而且非常的流畅,这样的动画并不需要 Canvas 这种重武器,简单的 DOM 就可以实现,SVG 真的是一个神器,不仅在实现图标,字体上特点鲜明,在实现柔性动画方面也独树一帜。SVG 依然是 DOM ,他有自己独有的 Animation 标签,但也支持 CSS 的属性,其实现动画的本质是依赖于线条填充,线条的变化,导致填充区域的改变,从而引起形状的变化。而线条则依赖于路径锚点,路径和锚点的改变,直接影响了线条的变化。

上面的案例,使用的是 GreenSock 的 SVG 动画插件 —— MorphSvgPlugin ,他可以实现不同 SVG 元素之间的相互转换,过渡非常平滑。

SVG 实现的动画比较局部和小巧,使用范围也比较狭窄,但是当我们实现复杂的柔性动画,甚至游戏的时候,就还是需要用 Canvas 来实现。

从上图我们可以看到龙的翅膀是一张图片,但是可以通过图片的局部的扭曲和变形,来实现煽动翅膀时带来的肌肉收缩和舒张。这样的动画是怎么实现的呢?这就要引出骨骼动画中,一个非常重要的概念:网格

这里我们比较浅显的讨论下这个概念,要实现图片的局部变化,我们就要把图片分块,分的每一块就称为网格,每个网格都有自己的顶点和边,顶点的位移会引起网格形状的变化,形状的变化就会带来所附属的图片的变化。网格的概念是不是很像路径和锚点,不论怎样的技术,在实现逻辑上都大同小异,重要的不是一直盯着不同和变化的部分,而是发现那些不变的地方,才能达到触类旁通的效果。

制作这样的动画并不复杂,你可以使用类似 Spine 和 DragonBones 这样的工具,但是做动画真的是一个体力活,你需要不断的调试,以求达到一种让人看起来舒服的状态。

总结

在大前端概念下,WEB 动画是一个非常绚烂又深邃的领域,甚至不只局限于前端,他更注重用户的交互体验,以及真实世界的虚拟化。这里我们也只讨论了这座大山的冰山一角,还有很多动画形式需要进一步研究和思考,例如:

  • 粒子动画
  • 特效动画
  • 3D动画
  • 数据可视化动画 ...

当我们更深入研究,就会发现,数学的重要性,审美的重要性,创意的重要性。技术只是工具,他所涌现出来的是一种对于美的追求和体验。虽然说的不明觉厉,但是真的值得好好思考一下。

参考

文章可随意转载,但请保留此 原文链接

非常欢迎有激情的你加入 ES2049 Studio,简历请发送至 caijun.hcj(at)alibaba-inc.com 。