如果您曾经编写过一个超过 10 秒、包含数十甚至数百个精心编排元素的动画,您就会知道避免可怕的“代码墙”有多么困难。 更糟糕的是,编辑由其他人(甚至 2 个月前的您自己)构建的动画可能会变成噩梦。
在这些视频中,我将向您展示专业人士用来保持代码整洁、易于管理和易于修改的技术。 脚本化动画使您有机会创建非常动态和灵活的动画。 我的目标是让您在享受乐趣的同时,不会被流程所困扰。
我们将使用 GSAP 进行所有动画。 如果您尚未使用它,您将很快了解它如此受欢迎的原因——工作流程优势非常大。
查看 CodePen 上的示例 SVG Wars: May the morph be with you. (Craig Roblewsky) 。
上面来自 Craig Roblewsky 的演示很好地展示了我希望帮助您构建的复杂动画类型。
本文面向那些对 GSAP 有基本了解并希望以更智能、更高效的方式处理代码的人员。 但是,即使您没有使用过 GSAP,或者更喜欢其他动画工具,我认为您也会对这些针对所有动画师面临的一些常见问题的解决方案感到好奇。 坐下来,观看并享受吧!
视频 1:技术的概述
下面的视频将快速向您展示 Craig 如何在 SVG Wars 动画中构建代码以及这些工作流程策略的众多优势。
虽然这是一个详细而复杂的动画,但代码却出奇地易于使用。 它是使用我们 GreenSock 在任何超过几秒的动画中使用的相同方法编写的。 此技术的秘诀在于两方面
- 将您的动画分解成更小的时间轴,并在主(父)时间轴中将其粘合在一起。
- 使用函数创建并返回这些较小的时间轴。
这使您的代码模块化且易于编辑。
视频 2:详细示例
我将向您展示如何使用创建和返回时间轴的函数构建序列。 您将看到如何将所有内容打包到一个大型时间轴中(没有模块化嵌套)会导致令人望而生畏的“代码墙”。 然后,我将动画分解成单独的时间轴,并使用一个参数化函数来完成所有繁重的工作,代码减少了 60%!
让我们回顾一下关键要点…
避免可怕的代码墙
一种常见策略(尤其对于初学者)是创建一个包含所有动画代码的大型时间轴。 虽然时间轴提供了大量适应这种编码风格的功能,但任何编程工作的基本现实都是,在一个地方放置太多代码会变得难以管理。
让我们升级代码,以便我们可以应用 Craig 在 SVG Wars 动画中使用的相同技术…
查看 CodePen 上的示例 Wall of Code 。
请务必检查“JS”选项卡中的代码。 即使对于像这样简单的事情,代码也可能难以扫描和编辑,特别是对于刚接触该项目的人来说。 想象一下,如果该时间轴有 100 行。 在脑海中解析所有内容可能是一件苦差事。
为每个面板创建一个单独的时间轴
通过将每个面板的动画分离到其自己的时间轴中,代码变得更容易阅读和编辑。
var panel1 = new TimelineLite();
panel1.from(...);
...
var panel2 = new TimelineLite();
panel2.from(...);
...
var panel3 = new TimelineLite();
panel3.from(...);
...
现在,快速扫描并查找panel2的代码变得容易多了。 但是,当创建这些时间轴时,它们都将立即播放,但我们希望它们按顺序播放。
没问题——只需按我们想要的任何顺序将它们嵌套在父时间轴中即可。
使用 add() 嵌套每个时间轴
GSAP 的时间轴工具(TimelineLite / TimelineMax)最强大的功能之一是能够根据需要无限深度地嵌套动画(将时间轴放置在其他时间轴内)。
使用 add() 方法,您可以将任何补间动画、时间轴、标签或回调添加到时间轴的任何位置。 默认情况下,内容将放置在时间轴的末尾,这非常适合排序。 为了安排这 3 个时间轴依次运行,我们将把它们添加到主时间轴中,如下所示
//create a new parent timeline
var master = new TimelineMax();
//add child timelines
master.add(panel1)
.add(panel2)
.add(panel3);
此阶段所有代码的演示
动画看起来相同,但代码更加精致且易于在脑海中解析。
嵌套时间轴的一些主要好处是,您可以
- 更轻松地扫描代码。
- 只需移动 add() 代码即可更改部分的顺序。
- 更改单个时间轴的速度。
- 使某一部分重复多次。
- 使用 位置参数 精确控制每个时间轴的位置(超出本文的范围)。
使用函数创建并返回时间轴
优化此代码的最后一步是创建一个生成每个面板动画的函数。 函数本身功能强大,因为它们
- 可以多次调用。
- 可以进行参数化以改变它们构建的动画。
- 允许您定义不会与其他代码冲突的局部变量。
由于每个面板都是使用相同的 HTML 结构和相同的动画样式构建的,因此我们可以通过使用函数创建时间轴来消除大量重复代码。 只需告诉该函数要操作哪个面板,它就会完成其余工作。
我们的函数接收一个单一的panel参数,该参数用于所有补间动画时间轴中的选择器字符串中
function createPanel(panel) {
var tl = new TimelineLite();
tl.from(panel + " .bg", 0.4, {scale:0, ease:Power1.easeInOut})
.from(panel + " .bg", 0.3, {rotation:90, ease:Power1.easeInOut}, 0)
.staggerFrom(panel + " .text span", 1.1, {y:-50, opacity:0, ease:Elastic.easeOut}, 0.06)
.addLabel("out", "+=1")
.staggerTo(panel + " .text span", 0.3, {opacity:0, y:50, ease:Power1.easeIn}, -0.06, "out")
.to(panel + " .bg", 0.4, {scale:0, rotation:-90, ease:Power1.easeInOut});
return tl; //very important that the timeline gets returned
}
然后,我们可以通过使用add()
将每个时间轴放置在父时间轴中来构建所有时间轴的序列。
var master = new TimelineMax();
master.add(createPanel(".panel1"))
.add(createPanel(".panel2"))
.add(createPanel(".panel3"));
包含完整代码的已完成演示
此动画的设计初衷是相对简单,并使用一个可以完成所有繁重工作的函数。 您的实际项目可能会有更多差异,但即使每个子动画都是唯一的,我仍然建议使用函数来创建复杂动画的每个部分。
查看 Sarah Drasner 在其精彩示例中提供的示例,该示例使用返回时间轴的函数来说明如何做到这一点!
当然,主 GSAP 页面动画也使用了相同的技术
GSDevTools
您可能已经注意到某些演示和视频中使用的花哨的时间轴控制器。 GSDevTools 旨在通过允许您快速导航和控制任何 GSAP 补间动画或时间轴来增强您的工作流程。 要了解有关 GSDevTools 的更多信息,请访问 greensock.com/GSDevTools。
结论
下次当你遇到一个中等复杂度的动画项目时,可以尝试这些技巧,看看它能给你带来多少乐趣,以及你可以多快地进行实验。当你的同事需要编辑你的动画时,他们会对你赞不绝口。一旦你掌握了模块化代码和利用 GSAP 的高级功能,它可能会为你打开一个全新的可能性世界。不要忘记使用函数来处理重复性任务。
与所有项目一样,你可能会遇到客户或艺术总监提出以下问题
- “你能把整个动画速度放慢一点吗?”
- “你能把中间那 10 秒的部分移到最后吗?”
- “你能加快结尾速度并让它循环播放几次吗?”
- “你能跳转到结尾部分,让我检查一下文字内容吗?”
- “我们能把这个我刚想到的、很蠢的新想法加到中间吗?”
以前,这些请求会引发恐慌并危及整个项目,但现在你只需说“给我两秒钟...”
其他资源
要了解更多关于 GSAP 及其功能的信息,请查看以下链接
- GreenSock 动画平台 (GSAP)
- GSAP 入门指南
- 官方 GSAP 视频培训
- GSAP 文档
- GSAP 展示
- GreenSock 支持论坛
- GSDevTools
- Club GreenSock (获取额外插件/工具)
CSS-Tricks 阅读者可以使用优惠券代码 CSS-Tricks 享受 Club GreenSock 会员资格 25% 的折扣,这将为您带来许多额外内容,例如 MorphSVG 和 GSDevTools(本文中引用)。有效期至 2017 年 11 月 14 日。
哇,这真是太棒了,非常感谢。
不客气!很高兴听到你喜欢它。
嗨,Carl,
一个使用 Greensock 创建和执行更多动画的绝佳动力。完美地解释了清晰的示例……
非常感谢
Manfred
之前在 YouTube 上观看过这些视频。很棒的见解!绝对很有帮助。期待看到更多此类面向教程的视频,演示插件或工作流程的不同技巧/窍门。
好东西,Carl!
嗨,Sean,非常感谢!很高兴在这里见到你。