CSS-Tricks Logo 彩蛋动画的制作

Avatar of Sarah Drasner
Sarah Drasner

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

当 Chris 首次开始 CSS-Tricks 的重新设计时,他向我展示了一些关于设计方向的屏幕截图,并建议我为 logo 制作一个动画作为设计更新的一部分。我对这个项目感到兴奋,我的脑海中立即开始浮现各种可能的动画和交互方式。

我最近一直在大量使用 GreenSock 动画平台 和 SVG。如果您不知道它,值得一试。它非常擅长 高性能动画复杂的时间轴 以及 跨浏览器动画稳定性,等等。

大约在这个时候,GreenSock 的 Jack 和 Carl 告诉我他们正在开发 MorphSVG 插件,它可以变形复杂的 SVG 形状,即使路径点的数量不同。我觉得这个项目将是学习这项新技术(并且非常棒)的好机会。同样在这个时候,Val Head 在 A List Apart 上发表了“为运动敏感性设计更安全的 Web 动画”,建议为导致大量运动的 UI 动画添加一个切换按钮。

第一次尝试

我感兴趣的是将 CSS-Tricks logo(“通配符选择器”星号)与类型 logo 本身的一些变形行为结合起来。“K”在 tricks 中,几乎本身就是一个半星,成为这个形状变形目标的一个好选择。

GreenSock 使用 MorphPlugin 发布的最酷的事情之一是名为 findShapeIndex 的辅助插件。如果您想特别注意形状变形的样式,此插件可以通过让您循环遍历补间点来帮助您选择最适合动画的变形类型。默认值为 auto,大多数情况下都可以正常工作。但是,当您想要稍微多一些控制时,能够使用此插件查看所有可能的补间变化是一个巨大的好处。您可以加载它,并将其从一个 ID 指向另一个 ID:findShapeIndex("#hex", "#star");,然后会出现一个不错的 GUI。

查看 Sarah Drasner(@sdras)在 CodePen 上的笔 findShapeIndex

但是,当我第一次创建它时,该插件尚不存在。因此,我发现要真正控制“K”和星号的“中间”状态,如果我设计一个半星,一个将两种状态结合起来的状态,可以使其看起来最佳。

k star morph

当我鼓励其他人尝试动画时,我发现强调我的动画项目并非一蹴而就,而且我通常不会只进行一次迭代就获得最终作品非常重要。这个项目也不例外。我的第一次迭代要精简得多(点击重新播放按钮查看动画)

查看 Sarah Drasner(@sdras)在 CodePen 上的笔 CSS-Tricks Logo 第一次尝试

我让星号和“K”变形,但最初的想法是将星号变形为几个点,这些点使用 TweenMax 内置的 Bezier 插件沿着路径旋转。星号圆圈通过使用非常简单的路径点数组进行旋转。

bezier = [
  { x: 0, y: 0 }, 
  { x: 0, y: 20 }, 
  { x: 20, y: 20 }, 
  { x: 20, y: 0 }, 
  { x: 0, y: 0 }
];

然后,当我将 curviness 设置为 2 时,我得到一个完整的圆圈。下面的演示表明,通过增加曲率,您可以超过创建简单曲线的点,并且 2 对于四点之间的圆角是最佳的。

tl.staggerTo(dS, 0.1, { bezier: {
    type: 'thru',
    values: bezier,
    curviness: 2
  }, opacity: 0, 
     ease: Linear.easeInOut }, 0.06);

查看 Sarah Drasner(@sdras)在 CodePen 上的笔 GreenSock Bezier 中曲率的演示

有关 GreenSock 中路径运动的工作原理的更多信息,请参阅这篇 David Walsh 博客文章

与其让“K”再次出现,我更希望它以自己的笔触重新绘制到屏幕上,这样会更好看。

drawSVG: '50% 50%' 使整个笔触看起来像是不存在,因为笔触的两侧都完全折叠了。然后,我可以在稍后将其填充色从 none 设置为黑色。

tl.fromTo(k2, 0.8, {
   drawSVG: '50% 50%'
 }, {
   drawSVG: true,
   ease: Power4.easeOut
 }, "begin+=1");
 tl.fromTo(k2, 1, {
   fill: "none"
 }, {
   fill: "black",
   ease: Power4.easeOut
 }, "begin+=1.6");

但是,在经历了这一切之后,我对结果有点不满意。它确实有效,但缺乏一些……活力和……吸引力?我向 Chris 寻求了一些艺术指导,他建议将字符变形为“CSS-TRIK*Z”然后再变回来。

进一步的设计改进

根据我在初次尝试中获得的经验,我决定我真的很喜欢“K”和星号。然后,我决定更进一步,让更多字符动起来。“C”、“K”和结尾的“S”显然都需要移动才能变成其他字符。从星号开始,我开始进行草图绘制。

我发现丑陋的故事板可以节省我很多时间。我只需 15 秒就可以记下这些视觉笔记,然后当我转到 Illustrator 完善我的想法时,我就有了计划。我在动画设计中学习到的最基本的事情之一是,设计所有内容,然后慢慢揭示元素非常有意义。

通过在科技主题内工作,很容易注意到字母形状与它们可能变形对应的关联。我探索了 icomoon.io 并看到了一个链接图标,如果我旋转一下,它看起来有点像“S”,还有 GitHub 分支图标,它类似于“T”,而我所需要做的就是在 Illustrator 文件中放置它们时调整路径数据以匹配 logo 中字母的宽度和高度。

为了补充星号,我想要一些类似行星的东西。我认为土星环可以变成 CSS 括号,它也有可能看起来像“K”。“S”和“Z”是一个非常简单的翻转变形,但是当我真正考虑“Z”时,它有可能看起来像代码括号:</>。我最初在括号之间添加了一些标签的打字效果,但这减慢了所有动画的速度以适应该运动,而且有点太繁忙了,所以我把它去掉了。同样,我的所有动画都经历了许多迭代阶段,有时我会花一段时间创建和编码一些最终没有被采用的内容。嘿,这就是演艺圈。

当我在 Illustrator 中工作时,我确保正确命名了我正在使用的所有部分,以便我可以在代码中找到它们。

layers in illustrator

原始 logo 已转换为轮廓,但如果没有,我需要将其转换为使用每个字母的路径数据。您可能会发现某些东西(例如 logo)是一个复合路径,很难操作。在这种情况下,您可以在字母之间绘制一条简单的线,打开路径查找器窗口,然后选择“分割”。这应该为您分割路径,以便您可以分别使用它们。

导出完整 SVG 时,我会优化我的代码,使其不臃肿且易于阅读。我通常使用 Jake Archibald 的 SVGOMG,它构建于功能强大的基于终端的 SVGO,但具有一个出色且有用的 GUI,因此您可以看到您正在导出什么。由于我花了所有时间命名每个路径并将它们放在易于理解的组中,因此我确保取消选中“清理 ID”和“折叠无用组”,否则我会剥离所有这些路径属性的标识。

最终动画开发

由于 GreenSock 的插件,变形本身非常简单。您可以从一个 ID 指向另一个 ID,它会为您完成繁重的工作。

tl.to(k, 0.2, {
    morphSVG: {
      shape: hstar
    },
    ease: Linear.easeNone
  });

在进行此操作的过程中,在时间轴中使用相对标签很有意义。

tl.add("begin");

这样我就可以确保所有动画都从时间轴上的同一点开始。这也意味着我可以跟踪它们何时应该完成它们的旅程。在这种情况下,您可以看到它们都在 2.5 左右结束,或者 "begin+=2.5"

在工作时,我将时间轴中的整个动画设置得慢得多,以便我可以真正分析每个动作——只需一行代码即可轻松实现。

tl.timeScale(0.4);

然后,当我完成所有动作后,我可以调整它,直到得到我认为适合该运动的时间刻度,在本例中为

tl.timeScale(1.2);

我通常在我的动画中不太使用线性缓动,但变形通常与平滑的线性缓动看起来非常不错。要可视化可用的不同类型的缓动,请查看此出色的 缓动可视化器 工具。我在这里谨慎地使用“back”类型的缓动,以强调线性缓动并引起我对想要优先处理和以略微夸张的方式强调的时刻的注意——在本例中,土星环变形或最终的星号变形。(点击虚线中的橙色切换按钮激活动画。您可能需要先点击重新运行。)

查看 Sarah Drasner(@sdras)在 CodePen 上的笔 CSS-Tricks Logo 动画

要使这个动画正常工作,至关重要的一点是确保我最初隐藏的内容不会出现,即使只是一瞬间,直到我准备好让用户看到它们。所以,我将最终显示的所有路径属性的 CSS 设置为 visibility: hidden;,然后在 JavaScript 中使用 TweenMax.set 将它们设置回可见。这样可以确保它们在 JavaScript 加载并能够使用动画逻辑隐藏元素之前保持隐藏状态。

我将动画中多次使用的任何 ID 都存储为变量,以避免多次查找。如果在动画过程中需要多次使用某个字母的路径数据,例如当需要某个元素多次缓动到相同的形状时,我也可以存储该路径数据。

var tPath = t[0].getAttribute("d");

使用 GSAP 的时间轴真正酷的一点是,为了能够在诸如点击交互之类的事件发生时前后播放整个动画,我可以先暂停时间轴,然后播放时间轴的第一轮迭代,并将其反向播放以实现切换效果。

$(dotActive).on("click", function() {
  if ($(this).hasClass("active")) {
    $(this).removeClass("active");
    master.reverse();
  } else {
    $(this).addClass("active");
    master.play();
  }
});

这是使用 jQuery 3.0 的 jQuery 代码,这是第一个支持 SVG 类操作的 jQuery 版本。我还为悬停设置了一个单独的缓动动画,以提醒查看者切换按钮作为触发器的事实,并使用名为 bloop 的函数来实现重复圆圈的弹出效果,以及在 mouseenter 事件上生效的缩放效果。

function bloop() {
  var tl = new TimelineMax();
  tl.fromTo(dotExpand, 0.75, {
    scale: 1,
    opacity: 1
  }, {
    scale: 5,
    transformOrigin: "50% 50%",
    opacity: 0,
    repeat: 3,
    ease: Sine.easeOut
  });
  return tl;
}

var hoverOn = new TimelineMax({
    paused: true
  }),
  dash = $("#dash");
hoverOn.add(bloop());

$(dotActive).on("mouseenter", function() {
  dotExpand.removeClass("hide");
  TweenMax.to(dash, 0.3, {
    scale: 1.3,
    transformOrigin: "50% 50%",
    ease: Sine.easeOut
  });
  TweenMax.to(dotActive, 0.3, {
    scale: 1.3,
    transformOrigin: "50% 50%",
    ease: Sine.easeOut
  });
  hoverOn.restart();
});

圆点需要在切换按钮之间来回移动,而时间轴的前向和反向播放非常适合这种行为。我只是在主时间轴中添加了圆点横向移动的动画,这样当它在第二个状态下反向播放时,它就会沿着虚线回溯它的轨迹,指示我们动画的状态。

就这样!一个漂亮的“彩蛋”Logo 变形动画。