在学习 Vue.js 的过程中,我开始构建免费的 Web 工具,这些工具涉及到 SVG 的探索,目标是学习一些关于这两者的知识! 让我们来看一下其中一个工具:一个生成 SVG 加载动画的生成器,它允许您在 SMIL 或 Sass 动画、不同的样式、颜色、形状和效果之间进行选择。 它甚至允许您粘贴自定义路径或文本,然后下载最终的 SVG、复制代码或在 CodePen 上打开演示。

它是如何开始的
三件巧合促使我构建了一个 SVG 加载动画生成器。
巧合 1:Sarah Drasner 的书
我第一次了解 Sass 循环是在 Sarah Drasner 的 SVG 动画 中。 她展示了如何使用 Sass 函数交错动画(例如在第 6 章“动画数据可视化”中所做的那样)。
我从那一章和 Sass 循环的可能性中获得了灵感。
巧合 2:一个 GIF
在人生的同一时期,我被要求复制一个“加载动画”元素,类似于苹果的旧经典动画。

我参考了 Sarah 的示例来实现它。 这是我最终得到的 Sass 循环代码
@for $i from 1 to 12 {
.loader:nth-of-type(#{$i}) {
animation: 1s $i * 0.08s opacityLoader infinite;
}
}
@keyframes opacityLoader {
to { opacity: 0; }
}
这定义了一个从 1 到 12 的数字变量(i
),它会随着每个 :nth-child
元素增加动画的延迟。 这是使用 Sass 仅用两行代码即可动画化任意数量元素的完美用例,从而节省了我为每个需要的延迟声明 CSS 的时间。 这是相同的动画,但使用原生 CSS 书写以显示差异
.loader:nth-of-type(1) {
animation: 1s 0.08s opacityLoader infinite;
}
.loader:nth-of-type(2) {
animation: 1s 0.16s opacityLoader infinite;
}
/* ... */
.loader:nth-of-type(12) {
animation: 1s 0.96s opacityLoader infinite;
}
@keyframes opacityLoader {
to { opacity: 0; }
}
巧合 3:一个想法
有了这些想法,我想到一个加载动画的“画廊”,其中每个加载动画都是由相同的 Sass 循环生成的。 我总是很难在网上找到这类东西,所以我认为它可能对其他人有用,更不用说我自己了。
我之前已经作为个人项目构建过类似的东西,所以 我最终构建了一个加载动画生成器。 如果你发现其中的错误,请告诉我!
一个加载动画,两种输出
在创建生成正确的 Sass 输出的生成器时,我被自己的开发者技能所阻碍。 我决定尝试使用 SMIL 动画 的另一种动画方法,这就是我最终决定使用的方法。
但后来我得到了一些帮助(谢谢,ekrof!)并且最终让 Sass 工作起来。
所以,我最终向生成器添加了两种选项。 我发现让这两种语言返回相同的结果是一个挑战。 实际上,它们有时会产生不同的结果。
SMIL 与 CSS/Sass
在此过程中,我了解了关于 SMIL 和 CSS/Sass 动画的很多知识。 以下是在构建生成器的过程中帮助我的几个关键要点
- SMIL 不依赖于任何外部资源。 它通过 SVG 标记中的呈现属性直接为 SVG 创建动画。 这是 CSS 和 Sass 都无法做到的。
- 当 SVG 作为图像或背景图像嵌入时,SMIL 动画会被保留。 可以直接在 SVG 内部添加 CSS
<style>
块,但当然,Sass 则不能这样做。 这就是为什么在生成器中选择 SMIL 选项时,可以选择下载实际 SVG 文件的原因。 - SMIL 动画看起来更流畅一些。 我找不到原因(如果有人对此有更深入的信息,请分享!)。 我认为这与 GPU 加速有关,但它们似乎都使用相同的动画引擎。

您可能会注意到两种语言之间动画链式的差异
- 我在 SMIL 中使用了
additive="sum"
将动画一个接一个地添加。 这确保每个新的动画效果都能避免覆盖之前的动画。 - 也就是说,在 CSS/Sass 中,W3C 指出,
[当] 多个动画尝试修改相同的属性时,列表中名称最接近末尾的动画将获胜。
这就是为什么应用动画的顺序可能会改变 Sass 输出的原因。
使用变换
在加载动画的样式中使用变换是一个大问题。 我已将 transform: rotate
内联应用于每个形状,因为这是一种将它们彼此相邻放置在圆圈中并使面朝向中心的方式。
<svg>
<!-- etc. -->
<use class="loader" xlink:href="#loader" transform="rotate(0 50 50)" />
<use class="loader" xlink:href="#loader" transform="rotate(30 50 50)" />
<use class="loader" xlink:href="#loader" transform="rotate(60 50 50)" />
<!-- etc. -->
</svg>
我可以使用 <animateTransform>
在 SMIL 中声明一个 type
(例如 scale
或 translate
)以将该特定变换添加到每个形状的原始变换中
<animateTransform
attributeName="transform"
type="translate"
additive="sum"
dur="1s"
:begin="`${i * 0.08}s`"
repeatCount="indefinite"
from="0 0"
to="10"
/>
但是,CSS 中的 transform
覆盖了应用于内联 SVG 的任何先前变换。 换句话说,原始位置重置为 0,并且显示的结果与 SMIL 生成的结果大不相同。 这意味着无论如何动画最终看起来都一样。

使 Sass 类似于 SMIL 的(不太漂亮)解决方案是将每个形状放在一个组 (<g>
) 元素中,并将内联旋转应用于组,并将动画应用于形状。 通过这种方式,内联变换不会受到动画的影响。
<svg>
<!-- etc. -->
<g class="loader" transform="rotate(0 50 50)">
<use xlink:href="#loader" />
</g>
<g class="loader" transform="rotate(30 50 50)">
<use xlink:href="#loader" />
</g>
<!-- etc. -->
</svg>
现在两种语言的结果非常相似。
我使用的技术
我使用了 Vue.js 和 Nuxt.js。 两者都拥有良好的文档,但我选择它们还有更具体的原因。
我喜欢 Vue 有很多原因
- Vue 将 HTML、CSS 和 JavaScript 封装为“单个文件组件”,其中所有代码都位于一个更容易处理的单个文件中。
- Vue 绑定和动态更新 HTML 或 SVG 属性的方式非常直观。
- HTML 和 SVG 不需要任何额外的转换(例如使代码与 JSX 兼容)。
至于 Nuxt
- 它有一个快速样板,可以帮助您专注于开发而不是配置。
- 它具有自动路由功能,并支持自动导入组件。
- 它具有良好的项目结构,包括页面、组件和布局。
- 借助元标记,它更容易优化 SEO。
让我们看看一些加载动画示例
我喜欢最终结果的一点是,生成器不仅仅是一个单一功能的工具。 使用它并没有唯一的方法。 因为它输出 SMIL 和 CSS/Sass,所以有几种方法可以将加载动画集成到您自己的项目中。
下载 SMIL SVG 并将其用作 CSS 中的背景图片
就像我之前提到的,当 SVG 用作背景图片文件时,SMIL 功能会被保留。因此,只需从生成器下载 SVG,将其上传到您的服务器,并在 CSS 中将其引用为背景图片即可。
类似地,我们可以将 SVG 用作伪元素的背景图片
将 SVG 直接放入 HTML 标记中
SVG 不必是背景图片。毕竟它只是代码。这意味着我们可以简单地将生成器中的代码放入我们自己的标记中,并让 SMIL 完成它的工作。
在内联 SVG 上使用 Sass 循环
这正是我最初想要做的事情,但我遇到了一些障碍。与其为每个动画编写 CSS 声明,我们可以使用生成器生成的 Sass 循环。循环针对已应用于输出 SVG 的 .loader
类。因此,一旦 Sass 编译成 CSS,我们就得到了一个不错的旋转动画。
我仍在努力改进这个功能
我最喜欢的生成器部分是自定义形状选项,您可以在其中添加文本、表情符号或任何 SVG 元素到组合中。

我想做的是为样式添加第三个选项,只使用一个元素,这样您就可以使用您自己的 SVG 元素。这样,需要处理的内容更少,同时允许更简单的输出。
这个项目的挑战在于处理许多事物的自定义值,例如持续时间、方向、距离和度数。对我个人来说,另一个挑战是更熟悉 Vue,因为我想回去清理那些凌乱的代码。也就是说,该项目是开源的,并且欢迎提交请求!请随时发送建议、反馈,甚至 Vue 课程推荐,特别是与 SVG 或制作生成器相关的课程。
这一切都始于我在一本书中读到的一个 Sass 循环。它不是世界上最干净的代码,但我对 SMIL 动画的强大功能感到震惊。我强烈推荐Sarah Soueidan 的指南,以更深入地了解 SMIL 的功能。
如果您对 SMIL 的安全性感到好奇,这是有充分理由的。曾经有一段时间,Chrome 将完全弃用 SMIL(参见 MDN 中的开头说明)。但是,该弃用已被暂停,并且(似乎)已经有一段时间没有讨论过了。
我可以使用 SMIL 吗?
此浏览器支持数据来自Caniuse,其中包含更多详细信息。数字表示浏览器从该版本及更高版本开始支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
5 | 4 | 不支持 | 79 | 6 |
移动/平板电脑
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 3 | 6.0-6.1 |
太棒了,我喜欢它!
谢谢! :)
xlink:href
属性已弃用,因此如果将其替换为href
属性会更好我对这件事的看法https://css-tricks.org.cn/on-xlinkhref-being-deprecated-in-svg/
我会留意这个问题,谢谢!上次我测试
href
时,Safari 出现了问题,从那时起我就使用xlink:href
版本,它仍然在所有地方都能正常工作。