不用 js实现渐变、虚线、跑马灯、可伸缩边框

822 阅读3分钟

最近遇到个需求,要求实现一个渐变色的边框,并且是虚线的,同时还要有动画。

有的朋友可能看到这里就要开骂了,估计要提刀找设计和产品怼回去了。

但其实我是可以理解的,因为这种花哨的边框想要用在一个类似于魔法框的地方,框住一个地方,然后交给 ai 处理。这样的交互设计可以很好的体现科技感,并且我也想尝试一下,就接了这个需求。

单看几个条件都好处理,css 已经支持了 border-image。

再不济用伪元素遮盖一下,clip-path镂空也可以

甚至我看到很多网站是直接放个视频就完了

但是我这次的需求最重要的是虚线,这就不好处理了。因为设置了边框为虚线后会忽略掉 border-image。

其实这个问题看起来很难,做起来也确实难。我搜到了张鑫旭大佬多年前的文章,就是专门讲这件事的

www.zhangxinxu.com/wordpress/2…

看完之后我受益匪浅,虽然我不能用他的方案(因为他的方案中,虚线是假的,样式会和浏览器有差异)

我尝试了很多方案,mask、clip-path、背景图等等,效果都不好。

绝望之际我想到了一个救星svg

div 做不到的事情,我 svg 来做。svg 可以设置 stroke,可以设置 fill,可以设置渐变色,渐变色还可以做动画。简直就是完美的符合需求

先写个空标签上去

<style>
.rect{
    width: 100px;
    height: 100px;
}
</style>
<div class='rect'>
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    </svg>
</div>

因为我需要 svg 尺寸跟随父容器变化,所以就不写 viewBox 了,直接设置宽高 100%。同时在里面画一个矩形,也是宽高 100%。

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width='100%' height='100%'>
    <rect width="100%" height="100%"></rect>
</svg>

现在长这样 image.png

接下来给 rect 设置填充和描边,边框宽度为 4px

<rect 
    fill="transparent" 
    stroke="red" 
    stroke-width="4" 
    width="100%" 
    height="100%"
></rect>

image.png

接下来我们给border 设置为渐变色,需要在 svg 中定义一个渐变,svg 定义渐变色还是很方便的,都是现成标签和属性直接就可以通过 id 取到。

<svg>
    ...
    <defs>
        <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" stop-color="lightcoral" />
            <stop offset="50%" stop-color="lightblue" />
            <stop offset="100%" stop-color="lightgreen" />
        </linearGradient>
     </defs>
</svg>

接下来给红色的 stroke 换成渐变色

<rect 
    fill="transparent" 
    stroke="url(#gradient)" 
    stroke-width="4" 
    width="100%" 
    height="100%"
></rect>

image.png

接下通过 stroke-dasharray 来设置虚线边框

mdn 上关于 dasharry的介绍在这里 developer.mozilla.org/zh-CN/docs/…

image.png

我给 rect 设置 dasharray 为 5,5

<rect 
    fill="transparent"
    stroke="url(#gradient)"
    stroke-dasharray="5,5" 
    stroke-width="4" 
    width="100%" 
    height="100%"
></rect>

image.png

这样渐变虚线边框就成了

接下来处理动画效果

动画分两种

  1. 线动,背景色不动
  2. 线不动,背景色动

这两种效果我都实现了

首先展示线动,背景色不动的情况

这种情况只要能想办法让虚线产生偏移就可以,于是我搜了一下,这不巧了吗,正好有个属性叫 stroke-dashoffset

image.png

于是就可以通过 css 动画来修改偏移量

<style>
.dashmove {
    animation: dashmove 1s linear infinite;
}

@keyframes dashmove {
    0% {
        stroke-dashoffset: 0;
    }
    100% {
        stroke-dashoffset: 10;
    }
}
</style>
<rect class="dashmove" .... ></rect>

ezgif-1bb6c3542c4ad7.gif

大功告成

接下来处理第二种情况,线不动,背景动

这种情况就更简单了,因为 svg 本身就支持动画

我们只需要在渐变色中增加一个animateTransform标签

<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
    ...
    <animateTransform
        attributeName="gradientTransform"
        type="rotat
        from="0 0.5 0.5" 
        to="360 0.5 0.5" 
        dur="1s" 
        repeatCount="indefinite" 
    />
</linearGradient>

ezgif-6b83b81feb0420.gif

接下来看一下拖拽的效果,这个很重要,因为我们不希望随着容器比例变化,会让边框宽度也变化。

给容器元素加上这三个属性,这个 div 就变成了可拖拽缩放的

.rect{
    //    ...
    resize: both;
    position: relative;
    overflow: auto;
}

看下效果

ezgif-58de40b814d0bb.gif

完美 🎉🎉🎉

在这里查看完整在线 demo stackblitz.com/edit/stackb…