如何使用 SVG 和 CSS 制作文字动画

Avatar of Robin Rendle
Robin Rendle 发布

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

前几天,我正在帮助我的朋友 Jez 处理他的时事通讯网站 Dept. of Enthusiasm,突然想到一个主意。如果我们让标题中的“enthusiasm”这个词稍微动起来会怎么样?例如,如果单词中的每个字母都充满活力地上下跳动呢?

就像这样

很酷吧?要构建这个东西,我知道我们可以使用 SVG 来创建文本,然后使用 CSS 来制作动画。每个字母都是一个带有自己类名的路径,这使得可以选择每个字母。也就是说,没有什么能阻止我们使用 HTML 和 CSS 来做到这一点。使用 SVG 只是当时我觉得合适的一种方法。

为了开始,我们前往 Figma 并将文本输入到单独的文本框中。我们这样做是为了当我们点击这里的“轮廓描边”菜单项时……

……我们拥有每个字母的单独矢量。这将有助于我们在导出 SVG 时,可以为每个元素添加正确的 CSS 类。一旦我们描绘了每个字母的描边,我们就可以编辑矢量中的点(但对于我们即将要做的事情,我们不需要这样做)

如果我们将所有文本都放在一个框中并点击“轮廓描边”,那么它将创建一个包含所有这些字母组合的单个矢量。然后它将创建一个带有坐标的单个路径,这对我来说很难进行样式设置,甚至很难理解那里到底发生了什么。

接下来,我将所有这些字母放入一个框架(Sketch 将其称为画板)并将每个单词放入一个组中。这样,当它们作为 SVG 导出时,每个单词都将位于自己的g标签中,这也有助于我们设置字母的样式

然后,我导出了 SVG——但是!——我必须确保在执行此操作时包含id选项。

如果我们不这样做,我们将为每个字母获得一堆path元素,但它们将没有id属性。

这是我们导出后的结果

我不确定其中有多少奇怪之处是我的问题,有多少是 Figma 的 SVG 导出问题,但我删除了那个<rect>元素,因为它是不必要的。然后我给body元素设置了一个背景,这样我就可以看到文本并删除 SVG 本身上的那些内联heightwidth属性

太棒了!现在我们可以进入有趣的部分:为单词中的每个字母制作动画。

如果你查看上面示例的 HTML,你会注意到有一个g元素,它的id与 Figma 中的框架名称相同。每个单词也有g元素,构成单词的每个path都将具有一个单独的id。(这就是为什么正确命名我们的框架和组,以及在任何设计应用程序中保持内容井井有条非常重要的原因。)

令我惊讶的一件事是每个path的导出顺序:它与我预期的顺序相反,其中M是“ENTHUSIASM”组中的第一个字母。所以,我稍微整理了一下,并确保每个字母都按正确的顺序排列。

为了使动画正常工作,我们首先将每个字母向下移动2px

g path {
  transform: translateY(2px);
}

这是因为我希望每个字母都跳动2px,我们稍后会讲到。我还注意到,通过此更改,我需要更新 SVG 的视口。否则,每个字母的底部会被切掉

<svg class="header" viewBox="0 0 146 13" fill="none" xmlns="http://www.w3.org/2000/svg">

我可能应该直接在 Figma 中重新定位框架内的文本并重新导出,但这对我需要的功能来说已经足够了。

现在我可以定位 SVG 中的第三个组(“enthusiasm”这个词)并将animation-count设置为无限

/* targets the word "enthusiasm" */
g:nth-child(3) path {
  animation-name: wiggleWiggle;
  animation-duration: 2.5s;
  animation-iteration-count: infinite;
}

上面的代码然后调用下面的wiggleWiggle动画

@keyframes wiggleWiggle {
  20%,
  100% {
    transform: translate(0, 2px); /* stay on the baseline for most of the animation duration */
  }

  0% {
    transform: translate(0, 0px); /* hop up */
  }
  10% {
    transform: translate(0, 2px); /* return to baseline */
  }
}

看到那个关键帧的开头——20%、100% 部分了吗?它的意思是“在动画的大部分时间里,将所有文本保持在基线上。”这就是给我们每个弹跳之间带来良好延迟的原因

我从一篇关于动画时序的非常好的文章中了解到这个技巧,这篇文章是 Geoff 写的,如果你即将开始学习 CSS 中的动画,我强烈建议你看看。

现在是乐趣所在:使用animation-delay属性,我们可以使每个字母在它前面的字母之后跳动。当然,我可以用更聪明的方法做到这一点,但我只是像这样使用了每个字母的id

#E {
  animation-delay: 0s;
}

#N {
  animation-delay: 0.1s;
}

#T {
  animation-delay: 0.15s;
}

#H {
  animation-delay: 0.2s;
}

#U {
  animation-delay: 0.25s;
}

#S_2 {
  animation-delay: 0.3s;
}

#I {
  animation-delay: 0.35s;
}

#A {
  animation-delay: 0.4s;
}

#S {
  animation-delay: 0.45s;
}

#M {
  animation-delay: 0.5s;
}

它确实很混乱,但是编写循环并不会节省我很多时间,而且我将来也不需要更新它,所以我认为它足够好了。就这样,我们差不多完成了!

现在,我们有一个弹跳的、充满活力的标题来打招呼。为摇摆的文字欢呼!