实现一个会动的渐变边框

1,889 阅读5分钟

现代网页设计中常常会涉及到渐变边框的使用,CSS的border-image 属性也提供了渐变色边框的支持,我们可以在其中传入一个 linear-gradient 函数来实现渐变效果。 但是这个属性是不能和虚线效果或者圆角效果等同时存在的,这就给我们带来了很大的限制。例如想要实现封面中那样的虚线 + 渐变 + 动画的效果,我们就得寻找别的方法。

你将学到的

  1. SVG 矩形绘制
  2. SVG 颜色渐变
  3. SVG 动画

用SVG实现虚线渐变边框

我们可以利用SVG来绘制边框的样式,然后把SVG图片作为元素的背景图进行加载。

SVG 矩形绘制

SVG是一套声明式的绘图系统,和HTML标签类似,我们想绘制什么图形就用相应的标签,再通过标签的属性进行图像样式的控制。绘制一个矩形的SVG代码如下所示:

<svg>
	<rect width="100%" height="100%" style="
		fill: none;
		stroke: black;
		stroke-width: 20px;
	"></rect>
</svg>

Pasted image 20230329215047.png

把这段代码放在HTML中,就可以在屏幕上画出一个矩形。我们把widthheight都设为100%,也就是填满浏览器提供的容器。这里的style属性里面其实就是CSS代码,SVG也是可以通过CSS控制的,其中除了可以使用常规的CSS属性之外,还有有一些SVG特有的属性,例如这里用到的三个属性。fill用于设置图形填充的样式,类似于canvasfillStyle,这里我们设置为 none,也就相当于绘制一个空心的矩形。stroke用于设置边框颜色,stroke-width用于设置边框粗细。 如果要把边框变成虚线也很简单,只需要在style中加上这一句

stroke-dasharray: 20px 10px;

Pasted image 20230329224923.png

可以看到我们的矩形边框变成了虚线。stroke-dasharray的两个参数分别表示短划线的长度和间隔的大小。我们也可以通过提供若干对的短划线和间隔长度来绘制不均衡的虚线,更多信息可以参考MDN的文档

SVG 渐变

目前我们已经完成了虚线效果,那么要怎么实现渐变的边框颜色呢?与CSS中的渐变类似,我们需要先声明一个 linear-gradient 节点,再将其应用于边框的颜色上。具体的代码如下:

<linearGradient id="gradient">
	<stop stop-color="#fcb045"></stop>
	<stop stop-color="#fd1d1d" offset="0.5"></stop>
	<stop stop-color="#833ab4" offset="1"></stop>
</linearGradient>

这个节点的效果相当于CSS中的 linear-gradient(#fcb045 0%, #fd1d1d 50%, #833ab4 100%);。也就是说我们的渐变起点颜色为#fcb045,50%处的颜色为#fd1d1d,渐变终点的颜色为#833ab4。我们给这个节点设置了一个id,用于后续在stroke属性中进行引用。

stroke: url(#gradient);

把我们刚才的矩形的stroke改为 #gradient 节点的引用,可以看到我们的边框已经变成了渐变色。

Pasted image 20230330001613.png

SVG 动画

给SVG添加动画非常的简单,因为SVG是可以直接被CSS控制的,所以我们只需要用 CSS animation 来改变SVG元素相应的属性就可以了。具体要改变的是 stroke-dashoffset 这个属性。我们将它的值设为10px来看看效果。

stroke-dashoffset: 10px;

Pasted image 20230330001535.png

可以看到边框的形状变得不一样了,因为该属性使得整个边框的虚线移动了 10px。所以我们只要通过一个CSS动画来不断改变stroke-dashoffset就可以实现边框旋转的效果了。

@keyframes border-animate {
	to {
		stroke-dashoffset: 30px;
	}
}

/* rect.style */
animation: border-animate 1s linear infinite;

这里我们把动画函数设置为 linear ,因为默认的 ease 函数会让边框的滚动变得不均匀。通过设置 infinite 来让动画持续进行。动画的最终效果设置为 stroke-dashoffset: 30px,是因为30px的效果刚好和0px是一样的(后一条短划线刚好走到前一条短划线的位置),这样可以保证动画的连贯性。最终效果如下图所示:

CPT2303300032-300x150.gif

我们再调整一下边框的样式来让它更符合设计图的要求,最后在需要这个边框的元素上将background设置为这个SVG图片就大功告成啦!最终的完整代码如下:

<!-- index.html -->
<div class="banner">
  <p>渐变</p>
  <p>边框</p>
</div>
/* style.css */
.banner {
  background: url('./border.svg');

  width: 300px;
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

p {
  font-weight: bolder;
  font-size: 400%;
  margin: 0;
  line-height: 95%;
}

p:first-child {
  color: #d63c45;
}

p:last-child {
  color: #833ab4;
}
<!-- border.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
  <style>
    @keyframes border-animate {
      to {
        stroke-dashoffset: calc(var(--stroke) * 2.75);
      }
    }
  </style>
  <linearGradient id="gradient" gradientTransform="rotate(45)">
    <stop stop-color="#fcb045"></stop>
    <stop stop-color="#fd1d1d" offset="0.5"></stop>
    <stop stop-color="#833ab4" offset="1"></stop>
  </linearGradient>
  <rect width="100%" height="100%" style=" 
            --stroke: 35px;
            stroke: url(#gradient); 
            stroke-width: var(--stroke); 
            fill: none; 
            stroke-dasharray: calc(var(--stroke) * 2) calc(var(--stroke) * 0.75);
            animation: border-animate 1s infinite linear;
        " />
</svg>

代码的运行效果如图所示:

CPT2303292053-300x200.gif

总结

相比于其他常见的使用 background + linear-gradient 和直接放图片的方法,用SVG来进行边框绘制主要有两个优势:

  1. SVG标签的结构和HTML很相似,属于声明式的绘图系统,只要了解HTML可以很轻松地掌握和修改。使用SVG可以很方便直观地实现虚线和渐变的效果。而直接放图片的修改成本就比较高了,需要进行图片的替换,可能还需要设计师的参与,这就降低了开发效率。如果用 background + linear-gradient 这种比较 hack 的方法,则可读性比较差,维护起来也很不方便。
  2. SVG可以直接和CSS交互,所以我们可以利用CSS动画来修改SVG的属性,实现动画的效果。也可以根据实际需要很方便地修改动画的属性,从而控制边框转动的频率、方向等等。

本文作者:wzkMaster,如果觉得文章有用欢迎点赞收藏哟~