从 After Effects 过渡到 CSS 过渡和关键帧
已发表: 2022-03-10网站看起来越来越像移动应用程序。 用户也越来越期待获得更像应用程序的体验。 从推送通知到离线模式,本机 Web 应用程序正在实现。
一旦网络应用程序像原生应用程序一样运行,设计交互也将改变以解决用例 - 即动画的普遍性。 从 Uber 到 Lyft,从 Snapchat 到 Instagram,动画推动了我们所有喜爱的应用程序中的交互。
动画设计实用技巧
当一个按钮被激活时会发生什么? 用户是否必须等待,不知道表单是否有效? 带有加载器的按钮可以在后台加载数据时保持查看器的参与度。 阅读相关文章 →
作为 Web 开发人员,我们需要一个良好的基础来创建兼具性能和可维护性的动画,这对于原生 Web 应用程序环境至关重要。 我们需要能够从 After Effects 转到 CSS 过渡、动画和关键帧。
什么是后效?
After Effects 是 Adobe 的一种行业标准产品,供图形和动画设计师用于对动画进行键控、合成和跟踪。 它是许多设计师使用的事实上的工具,通过将动画层导出到易于可视化的示例视频中来与团队交流想法,并附有动画开始和结束时间的参考表。
演示视频和参考表一起为开发团队提供了如何实现动画的良好基准。 视频用于查看整体画面,而参考表提供了制作或破坏动画交互的微小细节。
我们可以用 After Effects 做的事情
我们可以使用 After Effects 创建的内容仅受我们想象力的限制。 它可以为图像或视频提供无穷无尽的后期制作效果。 在网络的范围内,它提供了一个分享想法的平台。

考虑上面的红球。 使用 After Effects 为球设置动画,使其缓慢滚动到中间,暂停一秒钟,然后缓慢加速以退出视口。 移动、缩放、旋转甚至颜色变化的经典网络动画在 After Effects 中很容易完成,并作为要实施的动画的即时生成的需求文档(或视频或 GIF)。
入门所需的工具
随着 JavaScript、HTML5、CSS3 和许多其他语言成为网站接收流量的大多数主要用户代理的标准,使用这些工具批发变得越来越可行。 以下是实现动画时要牢记的一些关键技术。
CSS 过渡
CSS 过渡提供了一种控制 CSS 属性更改应用于元素的速度的方法。 可以使用自定义规则在定义的加速曲线上逐渐应用样式,而不是立即应用样式(没有过渡)。 例如,在一段时间内将背景颜色从黑色更改为白色。
transition-property: background-color; transition-duration: 3s;
在元素上使用此规则后,背景颜色将需要三秒钟才能改变,从黑色逐渐变为白色,经过灰色阴影。 这可以通过添加transition-timing-function来进一步定制,以计算中间值,以及transition-delay,以延迟动画的开始。
CSS 过渡适用于简单的交互,例如更改背景颜色或将元素移动到新位置。
使用 CSS 动画
CSS 动画使用航点对动画之间的中间步骤提供更精细的控制。 航点(或关键帧)是动画期间的固定时间点,当我们将某些样式应用于元素时。 然后我们使用定义的关键帧来布置动画应该是什么样子。
假设我们想要一个元素作为反弹动画。 元素需要上移,移回原来的位置,再上移一点,再移回原来的位置。 使用关键帧,我们可以将弹性效果分解为动画所需时间的百分比。
@keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } 40% { transform: translateY(-25px); } 60% { transform: translateY(-15px); } } .element { animation-name: bounce; animation-duration: 3s; }
与 CSS 过渡一样,开发人员可以配置很多选项。 我们可以使用animation-iteration-count
使动画无限重复,值为infinite
,甚至可以使用属性animation-direction
控制动画流动的方向。 大量的 CSS 动画属性为我们提供了细粒度的控制,以使动画与设计相匹配。
CSS 动画对于简短的重复动画很有用,例如展开、旋转和反弹。
使用 JavaScript
JavaScript 有多种用途,从 Raspberry Pi 服务器到客户端代码,但其核心用途之一仍然是更改元素上的类名。 更改类名是管理元素状态的一种简单而有效的方法。
一个示例是简单添加一个active
类,该类指示最初隐藏的组件开始制作动画。 考虑下面的球。 我们使用 JavaScript 添加一个使用 CSS 过渡属性触发动画的类。

该动画的第一部分可以使用 HTML、CSS 和 JavaScript 的简单组合来复制。
HTML:
<div class="ball"></div>
CSS:
.ball { width: 100px; height: 100px; color: red; transform: scale(0.25); transition: all 1s ease-in; } .ball.active { transform: scale(1.25); }
JavaScript:
setTimeout(function() { document.querySelector('.ball').addClass('active'); }, 500);
当超时( 500ms
)到期时,会在球的div
中添加一个active
类,这会改变transform
属性,然后触发transition
属性,它正在观察球元素上的transform
属性。 使用 JavaScript 更改 CSS 类不仅可以帮助我们管理组件的状态,还可以让我们进一步控制 CSS 动画和过渡之外的动画。
使用 JavaScript 控制动画有利于管理状态,根据用户输入或应用程序状态等动态因素触发事件。
从 Idea 到 After Effects 再到 CSS 和 JavaScript
想象一下,我们有一项任务,我们必须为页面上的元素设置动画。 让我们把这个元素变成一个红球。 球必须围绕页面旋转,以及放大和缩小。
After Effects 允许我们创建动画触发时交互效果的模型。 下面的运动球就是一个例子。 请注意红球是如何首先略微放大,然后开始围绕圆形循环加速并减速回到原来的位置。 只有这样,球才会缩小到原来的大小。

考虑在移动或停止之前球增长或缩小的位置上方的比例变化。 这是设计师在 After Effects 中精心设计的一个小功能,需要清楚地传达给开发人员,以免错过细节。
这就是为什么在从 After Effects 到开发人员之前需要做一些准备工作的原因。 我们不能简单地创建动画动画的视频文件,与开发人员共享它并收工。
清楚地传达我们的想法的一种方法是创建一个电子表格,详细说明动画所需的步骤。 根据动画的复杂程度,它可能是票证上的简单涂鸦、包含列表的文本文件或完整的电子表格。
步 | 动画 | 时间 | 细节 |
---|---|---|---|
1 | 球放大 | 1秒 | 带阴影的比例 1.25 |
2 | 球在一个圆圈中移动 | 2 秒 | 缩放 1.25,半径为 25 像素 |
3 | 球缩小 | 1秒 | 缩小到 1 |
传达有关动画信息的另一种方法是将其嵌入视频本身。 您可以在 After Effects 中直接执行此操作,添加重要信息,例如缩放程度、步骤数和其他正在发生的信息,以便为实施者提供上下文。 这使我们能够将演示视频用作普遍的事实来源。

这个从 After Effects 导出的视频文件充当了设计师和开发人员之间的一种合同形式。 有了共同的理解,我们可以使用讨论的工具来实现它——即 CSS 类、JavaScript 事件、CSS 转换、CSS 动画和 JavaScript 动画。
1.分解动画
寻找模式并注意时间。
首先要做的是为每个元素(或元素组)绘制动画的时间线。 我们需要了解动画在哪里相交,以便同步它们周围的时间和动画生命周期。 计划是复杂动画的关键,因此我们可以以可维护的方式逐步构建我们的解决方案,以满足未来的需求。
根据以上信息,我们将其分解为以下步骤:
- 初始化组件并等待触发。
- 触发后,按比例放大并扩大阴影。
- 之后,以
ease-in-out
的方式绕一圈移动。 - 然后,缩小尺寸并减少阴影。
大纲的好处是我们了解哪些组件必须存在于动画元素之外——例如,投影必须独立于球。 类似于概述一篇文章,分解动画可以组织我们对我们必须做的工作的想法。 大纲展示了动画背后的思考过程,并双重作为我们工作的文档。
2. 与利益相关者协商
我们可以简化一些领域吗? 动画的哪些部分是必须的? 我们可以同步时间吗?
一旦我们调查了完成任务所需的工作,我们就会讨价还价。 与设计师和产品所有者讨价还价是每个开发人员的责任。 实施者完全了解关键的容易实现的目标,什么可以做,什么不切实际。
动画很棘手,因为从动画中删除看似微小的细节可能会改变用户体验。 举一个基于开发的示例,更改动画的行为方式类似于更改我们可能从 API 调用接收到的响应负载:某些事情可以更改,但某些部分必须存在。
这是一个个案情况,基于我们与设计师的关系,以及与产品所有者的关系,并给出了发布时间表。 不建议要求删除某些动画,因为这超出了我们的专业领域。
讨价还价的一个好方法是同步时间或简化浏览器本机可能无法执行的动画,并避免使用 JavaScript 的动画,因为它们难以维护并且可能导致性能不稳定。 我们可以而且应该要求这些让步。
3. 计划攻击
知道每个元素的开始和结束状态应该是什么。 看看每个转换时间应该发生在哪里。 在 CSS 类中利用 BEM 清晰地应用动画。 理解为什么 JavaScript 应该被限制为支持 CSS 的原因。
让我们检查一下前面描述的动画。 五个州突然出现在我们面前:
- 初始状态,带有红色球和一些阴影;
- 具有较长阴影的放大版球;
- 球绕一圈运动;
- 球的缩小,连同它的投影;
- 返回初始状态,等待触发。
对于所有五个州,我们应该看看之前的风格是什么,之后应该是什么。 这将为我们提供有关实现它所需的动画工具类型的信息。
为此,我们从基本案例样式开始。 如果元素突然出现,这可能什么都不是,或者它可能是以前的样式,在链式动画的情况下。
状态 | 类名 | 期间 | 动画时间 |
---|---|---|---|
1 | 球 | (不适用,等待触发) | 不适用 |
2 | 球,球——放大 | 1秒 | 缓出 |
3 | 球,球--放大,球--盘旋 | 2 秒 | 缓进出 |
4 | 球,按比例放大的球,按比例旋转的球,按比例缩小的球 | 1秒 | 缓入 |
5 | 球 | (不适用,等待触发) | 不适用 |
通过在状态之间进行很少的样式更改来保持简单。 一旦我们确定了开始和结束状态,我们需要将它们标记为 CSS 类,以便它们可以轻松地应用于元素。 这使我们可以灵活地使用 JavaScript 来处理基于从元素可能依赖的 AJAX 调用接收的数据的类应用程序。
BEM CSS 非常适合我们的命名策略,因为我们将如何使用修饰符来表示正在进行的动画的状态。 如果动画足够通用,BEM 也是维护跨代码库工作的 DRY(“不要重复自己”)CSS 类的好方法。 我们将从块和元素标记开始,然后随着动画的进行而在修改器中分层。
这是一个示例模板类旅程:
// State 1 <div class="ball"></div> // State 2 <div class="ball ball--scale-up"></div> // State 3 <div class="ball ball--scale-up ball--circling"></div> // State 4 <div class="ball ball--scale-up ball--circling ball--scale-down"></div> // State 5 <div class="ball"></div>
我们从具有类 ball 的容器元素开始,它代表我们正在制作动画的红球。 随着动画在体验中迭代,我们的 BEM 类名也是如此,从放大到绕圈移动。 这是一种在应用样式时跟踪元素应该是什么样子的方法。
四、稳步实施
有了手头的大纲和可以使用的工具,我们应该逐个州地分析项目。
我们可以迭代地处理每个状态作为一个单独的项目,根据需要在前一个状态的基础上构建。 明确定义每个状态后,我们可以更专注于使代码干燥且易于阅读,而不是实现细节。 而且,当然,添加测试来覆盖我们的逻辑会很好。
初始状态
我们从一个简单的红色球开始,带有轻微的阴影。
.ball { background-color: #D24D57; width: 25px; height: 25px; margin: 5px; display: inline-block; border-radius: 50%; box-shadow: 0 8px 6px -6px #6C7A89; }
扩大
放大有两个部分:元素的大小及其投影。 我们使用一个名为scale
的关键帧,该关键帧由 DRY-ness 的放大和缩小共享来处理此动画。
@keyframes ball-scale { from { transform: scale(1); box-shadow: 0 8px 6px -6px #6C7A89; } to { transform: scale(1.25); box-shadow: 0 10px 6px -6px #6C7A89; } } .ball--scale-up { animation: ball-scale 1s ease-out forwards; }
循环(应用放大动画后)
我们使用一个名为circular
的关键帧,并移动它的transform-origin
属性以将元素从头开始移动一个圆圈。 请记住,只有在放大动画完成时才会发生盘旋。
@keyframes ball-circular { from { box-shadow: 0 10px 6px -6px #6C7A89; transform-origin: 50% -450%; transform: scale(1.25) rotate(0deg) translateY(-100%) rotate(0deg); } to { box-shadow: 0 10px 6px -6px #6C7A89; transform-origin: 50% -450%; transform: scale(1.25) rotate(360deg) translateY(-100%) rotate(-360deg); } } .ball--circling { animation: ball-circular 2s ease-in-out forwards; }
缩小(应用循环和放大动画后)
为了缩小,我们重用关键帧比例,使用animation-direction: reverse
来做与放大类相反的事情。 这使我们回到了原来的状态。
.ball--scale-down { animation: ball-scale 1s ease-in forwards; animation-direction: reverse; }
工作演示
如果我们将所有这些类组合成一个序列,我们将在 After Effects 中完成渲染的 CSS 表示。
点击球开始。
请参阅 CodePen 上 Chris Ng (@chrisrng) 的钢笔动画球。
结论
本文介绍的工具几乎不是最前沿的,但它们通常在大多数主流浏览器中都得到支持,这使得它们在今天仍然可用。
以前,实现动画很困难,因为它意味着使用 jQuery Animate 等外部工具来做一些简单的事情,比如在页面上移动元素。 今天,CSS 过渡和动画可以利用 GPU 本地高效地完成。
动画始终是开发人员、设计师和产品所有者之间的拉锯战。 诀窍是找到中间立场,让所有利益相关者都对产品的质量感到满意。 希望本指南能帮助您完成这一转变。