Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

动画:从 AE 到 Web #18

Open
JChehe opened this issue Apr 25, 2018 · 0 comments
Open

动画:从 AE 到 Web #18

JChehe opened this issue Apr 25, 2018 · 0 comments

Comments

@JChehe
Copy link
Owner

JChehe commented Apr 25, 2018

封面

呃~貌似好久没写文章了,感觉有点奇怪。废话不多说,但还是加点前戏吧。

不想听废话,直入主题>>

前戏

为何要写这篇文章

接下来因工作调整,应该就很少接触 H5 开发了。借此机会总结个人对动画的一些思考。

本文贴合实战,会结合笔者为数不多的开发案例进行讲解🤣。文章结尾也会提供相应文件让读者进行实践。

为何“别人”实现的动效恰到好处?

同一份设计稿给到不同开发者,结果可能千差万别。而结果主要由两部分体现——内在与外在。『内在』指的是代码质量、性能优化,『外在』则指的是视觉还原度和动效(交互)。

其中对于更直观的『外在』来说,视觉还原度高是前提,真正体现差距的是『动效』。因为设计师一般只给到“静态”的视觉稿,而无动画演示,更不用说提供动效搞(如 AE)了。

在这种情况下,页面的动效更多是由前端开发者自由发挥。因此对动效有钻研的同学优势尽显。我也曾问过这些同学,他们大多回答是:“多试多调”。因此,在设计师无『动效稿』提供的情况下,都需要花时间慢慢调整,以达到各方(本人、设计师、产品和需求方等)满意。若没有设计、动效等相关知识的学习与积累,恐怕是一只『没头苍蝇』。

关于动画的理论方面,笔者并没有积累,但推荐一些不错的资料(或许需要梯子)。同时也希望得到读者们的有效补充:

其实可以把『锅』扔给设计师

大多数前端开发者在设计和动效方面并没有太多积累,因而难以做出令人拍手称赞的效果。其实,这是设计师(和动效设计师)所擅长的领域。下表给出两者的对比:

* 设计师 前端开发 备注
是否擅长动画 大部分 少部分
如何生产动画 GUI 工具,如 AE 编写代码
效益 体现在以下几个方面:
1. 专业度
2. 实现效率:可视化 > 编写代码
3. 沟通成本
4. 各方满意度
5. ...

从上表可看出,将『动效设计』交给设计师能显著提高效益。

而在实际工作流程上:

  1. 设计师与前端开发的排期由『线性』变成『部分重叠』:设计师交付静态视觉稿后,前端开发就能进行视觉还原,设计师此时即可进入动效设计。
  2. 设计师将动效设计导出为视频,提前取得各方满意度,避免开发期间的反复沟通修改。

假设达成以上共识后,剩下的问题就是:如何还原『动效稿』?

apple 洗衣机
补间动画——Apple 逐帧动画——洗衣机

设计师输出的动效演示

注:全文『动效稿』均基于 Adobe After Effects(简称 AE)设计。

AE 到 Web 实现

其实,与『制造业』一样,实现方式就两种:

  1. 机械:通过工具直接导出
  2. 手工:手动取参数,通过掌握的 Web 技术实现

两者的优缺点比较:

* 机械 手工
效率
精度 视情况而定
定制化
情怀 因人而异

机械实现

机械代表着“未来、高效”。业界出现了很多优秀的工具,使得在浏览器渲染复杂动效成为了可能,且极大地提高了效率。

代表工具有:

  • Bodymovin 是 AE 的一个插件,用于将 AE 导出为 Web 动画(HTML、SVG 或 Canvas),支持 AE 部分特性。
  • lottie-web 是 Airbnb 团队的一个用于在 Web、Android、iOS 和 React Native 渲染 AE 动画的库。

可是『世界上本来就没有十全十美的东西』。机械化生产可能未必满足所有要求,生产环境上的要求就更加苛刻了。主要体现在:机械化生产导致介入难度高。若出现以下问题就比较棘手:

  1. 兼容性
  2. 在动画过程中插入自定义逻辑
  3. 工具自身的不完善
  4. 文件体积要求
  5. ...

无论如何,『机械化』是未来,期待它早日以完美的姿态到来。

手工实现

手工代表着“自定义、可控性”。无论世界如何工具化,总有一些人保持着对『手工』的热爱。

『手工』意味着从无到有的过程。需要我们参与这个过程的每一步。这也就使得我们拥有很强的自定义能力。这恰恰是『机械化』目前所不具备的特性。这也是本文重点阐述的内容

基于 AE 手工实现 Web 动画的主要工作有两点:

  1. 在动效稿上拿到元素的参数信息,如 x/y/z、rotation 等
  2. 通过适当的 Web 技术进行实现,如 CSS3/Canvas/SVG 等
如何手工取参

Web 动画一般分为 逐帧动画补间动画

显然,对于取参操作来说,逐帧动画比补间动画的工作量要大得多,但两者操作一致。所以下面以 补间动画 Apple 为例:

打开 apple.aep 文件,AE 界面如下:

AE 界面
AE 界面

点击『信息模块』预览面板的播放按钮或拖动『时间轴模块』的 标记3 即可预览动画。

根据 CSS3 animation 属性,我们需要获取以下信息:

  1. 动画持续时间 animation-duration
  2. 关键帧之间的缓动函数 animation-timing-function
  3. 动画延时时间 animation-delay

为了方便阐述,我们选取整个 Apple 动画中一个小圆圈(共 60 个)为代表,其余元素同理。
另外,由于该动画是一次性的,无需获取/设置动画的重复次数(animation-iteration-count)、运动方向(animation-direction)。

现在我们把目光投向『图层、运动模块』的 标记1

fps
标记1——FPS

由上图可得,FPS 为 12,即 1 秒 12 帧, 1 帧 0.0833 秒。

由上面 Apple 动画 可看出,每个圆的延时时间(animation-delay)、缓动函数(animation-timing-function)和持续时间(animation-duration)均不相同。换句话说,每个圈都是一个独立的补间动画,所有元素组合起来才是一个完整的补间动画。

双击『标记 2』,进入编组以查看每个圆的信息。

子元素——圆
子元素——圆

在『查看器』或『图层、运动模块』任意选中一个圆,展开其 变换 属性并单击 位置(标记1),即可在其右侧显示元素运动路径(标记2)。同时这也反映了属性的变化速率(即缓动函数(animation-timing-function),这方面会在后续详解。

位置 前面的时钟图标为蓝色时,代表有过渡动画。


某个圆的时间轴
某个圆的时间轴

结合上面知识,可从上图得出以下信息点:

  1. 该元素共有 4 个关键帧
  2. 只有 Y 轴上发生位移运动(绿线),X 轴上则是静止状态(红线)
  3. 延时时间为 1 帧(第 1 关键帧的时间点)
  4. 中间停留时间为 1 帧(第 2、3 关键帧之间)
  5. 过渡时间为 42 帧(3 * 12 + 7 - 1)。注意要减去延时时间(1 帧),下同。

因此,我们基于 CSS3 animation 实现该元素的补间动画:

<div class="circle-29"></div>
/* 默认将该园定位在第 2(或 3)关键帧的位置,以让元素默认显示屏幕内,便于开发调试。 */
.circle-29 {
    width: 60px;
    height: 60px;
    background-color: rgba(0, 224, 93, .7);
    position: absolute;
    left: 473px;
    top: 348px;
    border-radius: 50%;
    animation-name: circle29;
    animation-duration: 3.5s; /* 42 * (1 / 12) */
    animation-delay: 0.0833s; /* 1 * (1 / 12) */
    animation-fill-mode: both;
    animation-timing-function: ease-in-out;
}

@keyframes circle29 {
    0% {
        transform: translate3d(0, 1175px, 0);
    }
    61.90% { /* (2 * 12 + 3 - 1) / 42,注意要减去延时时间(1 帧)。下同。*/
        transform: translate3d(0, 0, 0);
    }
    64.29% { /* (2 * 12 + 4 - 1) / 42 */
        transform: translate3d(0, 0, 0);
    }
    100% {
        transform: translate3d(0, -1225px, 0);
    }
}

这样就完成了某个圆的补间动画了。虽然繁琐,但省去了反复试验的时间,基本做到一次开发,各方满意的效果。

See the Pen ae2web-circle by Jc (@JChehe) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

其余元素按照以上步骤即可完成整个动画。

假设没有动画演示和动效稿,仅凭个人感觉,编码完成一个由 60 多个元素组成的动画,简直难于上青天(对于笔者来说)。

也许你对 animation-timing-function 存在误解

细心的读者可能发现:如果第 1、2 关键帧和第 3、4 关键帧的缓动函数不相同时,该怎么办?

首先部分人可能对 animation-timing-function 存在误解:它是作用于整个 @keyframes 规则的。❌

对 timing-function 的错误认识

其实缓动函数是作用于 @keyframes 规则内的关键帧。若未为关键帧指定 animation-timing-function,则从其元素取得 animation-timing-function

更严格地说,缓动函数是应用在属性上。当关键帧有指定 animation-timing-function 时,则该缓动函数会影响该关键帧内所有属性,而每个受影响的属性,其缓动效果会结束在下一个有指定同样属性的关键帧。

举个例子:

.box {
    width: 100px;
    height: 100px;
    background-color: #6190e8;
    animation: move 2s ease both;
}

@keyframes move {
    0% {
        animation-timing-function: linear;
        transform: translateX(0);
        opacity: 1;
    }
    50% {
        opacity: .5;
    }
    100% {
        transform: translateX(100px);
        opacity: 1;
        animation-timing-function: ease-in-out; /* 无用多余 */
    }
}

在 0% 关键帧中指定的 animation-timing-function: linear 会对 transformopacity 属性有效。但因为 50% 关键帧未指定 transform 属性,所以 animation-timing-function: linear 对它生效至有指定 transform 属性的关键帧,即 100% 关键帧

对于 opacity 属性,因为 50% 关键帧未指定 animation-timing-function,所以它会取 .box 元素上指定的 ease 缓动函数。

简言而之:

  • transform 属性:只有 0% 和 100% 两个关键帧,关键帧之间的过渡函数是 linear。
  • opacity 属性:0% ~ 50% 关键帧之间的缓动函数是 linear,50% ~ 100% 关键帧之间的缓动函数是 ease。

综上所述,可在关键帧上指定不同的缓动函数,以满足属性在各个关键帧间不同的变化速率。

更强大的 cubic-bezier

细心的读者可能又发现:缓动函数碰巧是 预定义的关键字 还好,但如果是以下这种情况呢?

复杂的缓动函数

显然浏览器预定义的关键字无法还原这些类型的缓动函数,但浏览器提供了强大的 cubic-bezier() 方法。翻译过来就是三次贝塞尔曲线。因此,我们可以通过该方法自定义缓动函数。

想了解贝塞尔曲线的更多知识,可阅读 《贝塞尔曲线扫盲》

AE 时间轴 上呈现的是属性的变化路径,其未必与变化速率(即缓动函数)完全一致。因为它们的 X/Y 轴含义不同。

AE 与 CSS3 animation 对比

如上图所示,AE 是属性随着时间而变,CSS3 animation 是动画进度随着时间而变。然而属性的变化是有方向的,动画进度是永远向前的

举个例子:

AE:
AE 的时间轴
AE 属性变化是有方向的

对应 CSS3 animation-timing-function
CSS3 animation
动画进度永远是向前的

如上面二图所示,下图是上图的速率变化(缓动函数)。理清 AE 与 CSS3 animation 的对应关系后,剩下的问题就是:如何通过 cubic-bezier() 表示图中的 CurveACurveB

也许有工具可从 AE 直接导出(欢迎读者们提供链接),但本文为了简单起见,推荐使用 CeasarCubic-Bezier.com 这类可视化工具直接模拟生成。

因此,上述补间动画的缓动函数可表示为:

@keyframes ae2css {
    0% {
        animation-timing-function: ease-out;
    }
    23% {
        animation-timing-function: ease-in;
    }
    50% {
        animation-timing-function: cubic-bezier(0.5, 0, 0.5, 1.5);
    }
    76% {
        animation-timing-function: cubic-bezier(0, 0, 0, 1);
    }
    100% {
    }
}

总结

本文基于实际案例总结出 AE 到 Web 动画的实现方法。相对于『无动效稿』的反复编码尝试,该方法无疑能提高效益。当然,『手工』不能胜任复杂的动画(如 SVG 的变形动画(Morphing)),并且低效。因此,业界在『机械/工具化』方面不断推陈出新,涌现出许多优秀的工具,让复杂动画在各终端上得以展现。无论如何,学习更多知识总没错!

最后,感谢你的阅读!

案例演示

Apple 补间动画整体效果演示(一次性动画,请点击 "RERUN" 按钮重播):

See the Pen ae2css-apple by Jc (@JChehe) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
项目 Apple Joy&Apple 洗衣机
动画类型 补间动画 补间动画 逐帧动画(APP 背景图)
体验链接 Apple Joy&Apple 洗衣机
效果展示 Apple Joy&Apple 洗衣机
视频外链(若 gif 加载失败,可点击视频外链) Apple Joy&Apple 洗衣机

素材下载

参考资料

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant