让我们看看如何将 CSS 中的 border-image
属性与围绕边框移动的 SVG 动画结合起来。 在此过程中,我们将介绍如何手工制作可调整大小的九宫格动画 SVG,您不仅可以使用它来重新创建效果,还可以根据自己的需要进行定制。
这是我们正在制作的内容

这实际上是我正在进行的一个夺旗谜题 The Skull 的一部分,旨在探索 Arduino 及其微控制器的内部结构。 我搜索了如何像这样为边框设置动画,但找不到任何有用的示例。 我找到的大多数内容都与 蚂蚁行进 有关,但不幸的是,stroke-dasharray
技巧不适用于骷髅,更不用说更复杂的形状了。
因此,本着学习和分享的精神,我在这里与您一起撰写这篇博文!
background
还是 border-image
?
我们应该使用 起初,我甚至不知道 border-image
是什么。 在我的第一次尝试中,我尝试使用 ::before
伪元素,并为其 background-position
属性设置动画。 这让我走到了这一步
如您所见,它确实有效,但要完成边框,至少需要八个不同的元素(或伪元素)。 这样杂乱 HTML 不是理想的做法。
我在以色列 CSS 开发人员 Facebook 群组中发布了一个问题,每个人都向我指出了 border-image
属性。 它完全按照其字面意思执行:使用图像(或 CSS 渐变)作为元素的边框。
要使用 border-image
,您必须提供一个以九宫格方式使用的图像(想想图像上的井字棋棋盘)。 这九个区域中的每一个都代表边框的不同部分:顶部、右侧、左侧和底部,四个角中的每一个,以及中间(被忽略)。
例如,如果我们只需要静态骷髅,我们可以 利用 SVG 模式 将骷髅重复九次。 首先,我们使用骷髅的路径定义一个 24×24 的模式,然后使用此模式作为 72×72 矩形的 fill
<svg version="1.1" height="72" width="72" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="skull-fill" width="24" height="24"
patternUnits="userSpaceOnUse">
<path d="..." fill="red"/>
</pattern>
</defs>
<rect fill="url(#skull-fill)" width="72" height="72" />
</svg>
接下来,我们定义一个边框并在目标元素上设置 border-image
.skulls {
border: 24px solid transparent;
border-image: url("https://skullctf.com/images/skull-9.svg") 24 round;
}
我们得到一个由骷髅组成的边框
添加 SVG 动画
现在我们可以为这些骷髅设置动画了! 它有效,嗯,在大多数情况下。
我们的想法是为边框图像中的每个区域创建不同的动画。 例如,在左上角,我们有一个骷髅从右到左移动,而第二个骷髅同时从上到下移动。
我们将为运动设置 transform
属性的动画。 我们还将 利用 SVG 的 <use>
来避免为每个骷髅重复冗长的 <path>
定义
<svg version="1.1" height="96" width="96" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
@keyframes left {to {transform: translate(-32px, 0)}}
@keyframes down {to {transform: translate(0, 32px)}}
</style>
<defs>
<path id="skull" d="..." fill="red"/>
</defs>
<!-- Top-left corner: one skull goes left, another goes down -->
<use href="#skull" x="0" y="0" style="animation: down .4s infinite linear"/>
<use href="#skull" x="32" y="0" style="animation: left .4s infinite linear"/>
</svg>
那里的 SVG 动画语法可能看起来很熟悉,因为与其使用某种 SVG 特定的语法(如 SMIL),它只是使用 CSS 动画。 很酷,对吧?
这是我们得到的结果

如果我们添加一个网格,我们可以看到此动画也覆盖了部分顶部和左侧边缘

在添加了其余三个边框后,它开始变得更加令人印象深刻,从而完全覆盖了边框图像的所有八个区域
<svg version="1.1" height="96" width="96" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
@keyframes left {to {transform: translate(-32px, 0)}}
@keyframes down {to {transform: translate(0, 32px)}}
@keyframes right {to {transform: translate(32px, 0)}}
@keyframes up {to {transform: translate(0, -32px)}}
</style>
<defs>
<path id="skull" d="..." fill="red"/>
</defs>
<!-- Top-left corner: one skull goes left, another goes down -->
<use href="#skull" x="0" y="0" style="animation: down .4s infinite linear"/>
<use href="#skull" x="32" y="0" style="animation: left .4s infinite linear"/>
<!-- Top-right corner: one skull goes up, another goes left -->
<use href="#skull" x="64" y="0" style="animation: left .4s infinite linear"/>
<use href="#skull" x="64" y="32" style="animation: up .4s infinite linear"/>
<!-- Bottom-left corner: one skull goes down, another goes right -->
<use href="#skull" x="0" y="32" style="animation: down .4s infinite linear"/>
<use href="#skull" x="0" y="64" style="animation: right .4s infinite linear"/>
<!-- Bottom-right corner: one skull goes right, another goes up -->
<use href="#skull" x="32" y="64" style="animation: right .4s infinite linear"/>
<use href="#skull" x="64" y="64" style="animation: up .4s infinite linear"/>
</svg>
这为我们提供了一个完整的回路

将所有内容组合在一起,我们将刚刚创建的动画 SVG 作为 border-image
使用,并获得所需的结果
我可以整天玩这个……
一旦我让它工作起来,我就开始调整动画属性。 这是使用 SVG 而不是 GIF 的优势之一:更改动画的本质就像更改 SVG 源文件中的一个 CSS 属性一样简单,并且您可以立即看到结果,更不用说更小的文件大小(尤其是在处理渐变时)、完整的颜色支持和清晰的缩放。
首先,我尝试查看如果我将动画时间函数更改为 ease
会是什么样子
我们还可以使骷髅在红色和绿色之间淡入淡出
我们甚至可以使骷髅在绕着高分表移动时改变方向
转到 JavaScript 选项卡,您可以在其中调整 SVG 源代码并亲自尝试。
房间里的大象 🐘(咳咳,Firefox)
当我第一次让它工作时,我非常高兴。 但是,您应该了解一些注意事项。 首先也是最重要的是,由于某种原因,Firefox 不会渲染边框边缘的动画,而只渲染角上的动画

有趣的是,如果我将 SVG 更改为具有相同动画的 GIF,它可以完美运行。 但随后 Chrome 上的边框停止动画!🤦♂️
无论如何,这似乎是一个浏览器错误,因为如果我们将 border-image-repeat
属性更改为 stretch
,Firefox 会为边框设置动画,但结果有点古怪(尽管它可能适合页面的主题)

将 border-image-repeat
值更改为 space
似乎也有效,但前提是元素的宽度不是骷髅大小的整数倍,这意味着动画中会有一些间隙。
我还发现了一些视觉问题,例如当容器大小不是补丁大小(在本例中为 32px)的倍数时,例如骷髅上的细黑线。 我怀疑这与某些浮点数舍入问题有关。 在放大时,它也容易出现问题。
并不完美,但肯定完成了! 如果您想查看最终版本的实际效果,欢迎您查看 The Skull 的高分 页面。 希望很快就会有您的名字出现在上面!
我希望我的客户有预算来做这个 :) 来自波兰的问候。
谢谢! 我也希望如此 :)
太疯狂了,我要为我的整个背景设置动画。
太棒了! 请告诉我结果 :)
好技巧,写得很好,谢谢!
您能否详细说明“加载上述(内联)SVG 的技巧”? 您是否使用它是因为某些 CSS 属性无法使用 URL 片段? 我之所以这样问,是因为今天早上我尝试使用指向动画 svg(内联在文档中)的 URL 片段定义
cursor
,但它没有呈现。 我的主要动机是检查浏览器是否呈现外部 SVG 中定义的动画。我尝试使用
marker-mid
实现您的动画,但收效甚微,而border-image
显然是正确的方法。Guillaume!
没错,正如 此处所述。 您是否已经解决了这个问题,或者您是否仍然需要一些帮助?
您好,Uri,
抱歉,我看不出链接部分与我的问题有什么关系。
我希望你能解释一下,为什么你在本节的两个 CodePen 中使用
Blob
+createObjectURL
来为border-image
赋值。我之前也用过这个“技巧”,但记不清为什么要用它了。似乎无法将某些 CSS 图片属性分配给指向页面片段的 URL,例如
url(#fragment)
,而element(#fragment)
目前仅受 Firefox 支持。我想这就是我一直在等待的答案。抱歉,我可能没有正确理解你的问题!如果我记得没错,我之前也尝试过
url(#fragment)
,但它不起作用。看起来唯一合理的方法是使用 Blob URL,因为片段和数据 URL 都没有奏效。我不知道
element(#fragment)
。很高兴学习新东西!不错!我记得大约10年前在我的 DA 页面上用 SVG 边框做过一些花样。
实际上刚刚检查了一下,它在当前的移动版 Firefox 和 Chrome 上仍然有效。
https://deviantart.com/fli-c/journal/pfft-SVG-journal-skin-367755371
下午好,我在 SVG 中使用了更简单的动画来制作 border-image。我有一个以复杂方式绘制的产品卡片,在一两个地方有一些闪烁的蓝色线条。因此,当我为它们制作动画时,我的电脑、手机等设备会出现大量延迟,就像 border-image 正在消耗性能一样。你能帮我解决这个问题吗?
您好,
我正在尝试复制您的自定义边框技巧,但卡在了第一个 SVG 动画级别——我并没有真正理解它。您是如何将 SVG 指向您自己的 SVG 上传图标的?然后您是如何将其输出为 GIF 的?任何帮助都将不胜感激!
谢谢