前几天,我正在帮助我的朋友 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 本身上的那些内联height
和width
属性
太棒了!现在我们可以进入有趣的部分:为单词中的每个字母制作动画。
如果你查看上面示例的 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;
}
它确实很混乱,但是编写循环并不会节省我很多时间,而且我将来也不需要更新它,所以我认为它足够好了。就这样,我们差不多完成了!
现在,我们有一个弹跳的、充满活力的标题来打招呼。为摇摆的文字欢呼!
这是关于该想法的另一种实现方式,其中字母保留为网页文本并使用 Splitting.js。
我尝试过使用 SVG TextPath——并不完美,但你明白了!
查看 Chris Dowling 的 CodePen 作品
文本路径演示 (@gingerchris)
在 CodePen 上。
这很酷但很简单。另外,有没有办法在 CSS 中编写循环,或者是否必须使用 SCSS 或其他东西?
……以及使用 SMIL 的纯 SVG。无需库(好吧,为了兼容预 Blink Edge,你需要FakeSmile)和可访问文本。唯一的缺点是您需要估计文本的整体宽度。
查看 ccprog 的 CodePen 作品
使用 SMIL 制作跳动文本 (@ccprog)
在 CodePen 上。
我非常喜欢 SVG,但由于这是一种一次性的
<h1>
效果——我立刻想到将每个字母都包装在它自己的<span>
中,并通过 CSS 自定义属性使用顺序动画:结合calc()
、var()
,并为每个字母分配它自己的--i
值来计算各个字母的延迟。查看 r-i-c-h 的 CodePen 作品
CSS 自定义属性顺序动画 (@r-i-c-h)
在 CodePen 上。
但这可能会破坏 a11y。
版本 2:现在 HTML 更漂亮了,但有一个[丑陋的] JS 解决方案来代替导入 splitting.js 的需求……
很酷的东西!如果你使用 nth-child,你可以在任何长度的文本上运行波浪:)
对于 SVG 动画初学者来说,这是一篇不错的文章。