实现多个渐变色叠加的边框

本文最后更新于:2024年8月13日 下午

实现多个渐变色叠加的边框

如何实现下面这个由两个渐变色叠加的边框效果:

对于单个渐变色的边框可以用border-image轻松实现

1
2
3
4
5
6
7
.border-image-demo{
margin: 10px 0;
width: 200px;
height: 100px;
border: 2px solid;
border-image: linear-gradient(135deg, skyblue, purple) 1;
}

但这个方式存在两个问题:

  1. border-image只能接受一个渐变色,无法叠加多个渐变色
  2. border-image无法通过border-radius实现圆角

方法一:border-image+overflow

这一方法是在原有border-image方法上的改进,既然使用了border-image属性的元素无法通过border-radius属性实现圆角,那么可以给该元素添加一个父元素,给父元素设置border-radius属性,并设置overflow:hidden,以此来实现边框的圆角效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.border-image-demo-container{
margin: 10px 0;
width: 206px;
height: 106px;
border-radius: 5px;
overflow: hidden;
}

.border-image-demo{
width: 200px;
height: 100px;
border: 3px solid;
border-radius: 50px;
border-image: linear-gradient(135deg, skyblue, purple) 1;
}

但是也可以看到,这种方法存在两个问题

  1. 内部的黑色部分(内容部分)仍为方形,棱角分明
  2. 父元素的圆角不能太大,一但偏大就会出现边框断裂的问题

这是因为带有border-image的子元素本身是没有任何变化的,只是父元素中通过设置border-raduis对子元素进行遮挡而已,因此当父元素的圆角遮住了子元素的边框宽度后,子元素的边框便“断裂”了

方法二:多border-image元素叠加

此方法可以解决border-image不能使用多个渐变色的问题,既然一个border-image无法使用多个渐变色,那就用多个元素并设置border-image进行叠加,即可实现多渐变叠加的效果。

1
2
3
4
<div class="container">
<div class="mask1"></div>
<div class="mask2"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.container{
width: 200px;
height: 100px;
background-image: linear-gradient(100.9deg, #112531 -1.03%, #111111 37.46%, #000001 96.14%);
position: relative;
margin-bottom: 10px;
}

.mask1{
position: absolute;
width: 100%;
height: 100%;
border: 2px solid;
box-sizing: border-box;
border-image: linear-gradient(125.19deg, rgba(208, 208, 242, 0) 48.74%, rgba(223, 223, 252, 0.6) 98.12%) 1;
z-index: 1;
}

.mask2{
position: absolute;
width: 100%;
height: 100%;
border: 2px solid;
box-sizing: border-box;
border-image: linear-gradient(312.62deg, rgba(105, 124, 159, 0) 81.16%, rgba(255, 255, 255, 0.72) 99.61%) 1;
z-index: 1;
}

这种方法实现了浮于子元素上方的多渐变叠加的边框,但同样无法实现圆角的问题,此外这个方法的缺点显而易见,每个添加渐变都需要添加一个元素,很不方便。

方法三:clip-path

这种方法与方法一非常相似,方法一是通过添加父元素并设置overflow:hidden来对边框进行遮挡,而这种方法则是通过clip-path对元素本身进行裁剪。

1
2
3
4
5
6
7
8
.clip-path-demo{
width: 200px;
height: 100px;
border: 3px solid;
border-image:linear-gradient(135deg, rgba(123,123,252), rgba(0,253,252)) 1;
margin: 10px 0;
clip-path: inset(0 round 5px);
}

首先还是通过border-image设置渐变边框,之后通过clip-path属性对元素进行裁剪。clip-path: inset(0 round 10px),其中inset()是矩形裁剪,inset(0 round 10px)表示为一个与父容器完全贴合的容器,并且其border-radius10px,将这个元素之外的内容全部裁剪不可见。

inset()方法的位置信息有四个可选项,分别对应距离上、下、左、右四条边的距离,round为可选参数,其同样可以使用四个数值分别描述四个角的圆角数值。

这个方法的缺点也和方法一一样:

  1. 内部的黑色部分(内容部分)仍为方形,棱角分明
  2. 裁剪的圆角不能太大,一但偏大就会出现边框断裂的问题

方法四:background-image

在对border-image尝试无果后,便开始考虑通过background-image来实现这个效果,最常用的方法是给出一个宽高都略大于目标元素的div标签,设置其background-imageborder-image属性,将其放置在目标元素的下方,模拟出了一个边框。

1
2
3
4
<div class="background-image-demo-container">
<div class="background-image-demo-content">
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.background-image-demo-container{
margin: 10px 0;
width: 206px;
height: 106px;
position: relative;
border-radius: 20px;
background-image:
linear-gradient(135deg, rgba(123,123,252,0.4), rgba(0,253,252,0.4)),
linear-gradient(45deg,rgba(133, 208, 84, 0.4) 48.74%, rgba(23, 23, 232, 0.6) 98.12%);
}

.background-image-demo-content{
width: 200px;
height: 100px;
position: absolute;
top: 3px;
left: 3px;
border-radius: 20px;
background-color: black;
}

或者也可以不用两个元素,而用::after替代

1
2
3
4
5
6
7
8
9
10
.background-image-demo-container::after{
content: "";
width: 200px;
height: 100px;
position: absolute;
top: 3px;
left: 3px;
border-radius: 20px;
background-color: black;
}

左侧为单个渐变的效果,右侧为两个渐变叠加的效果,可见多个渐变叠加得以实现。同时也可以通过border-radius属性实现圆角。但这种情况下,如果需要该半透明的边框叠加在图片上方,则无法实现。

方法五:mask-image

为了将边框浮于元素上方,便思考有没有一种方法能够将元素裁剪为一个环,首先想到的是mask-image,他能够定义一个蒙版,来遮挡住元素,mask-image接收图片或者渐变色作为参数,而线性渐变无法实现效果,其只能实现渐隐的效果,因此采用径向渐变来进行蒙版的构建。

1
2
3
4
5
6
7
8
9
10
11
12
.mask{
content:'';
width:200px;
height:100px;
border-radius:50px 0;
position:absolute;
top: 0;
left: 0;
background: linear-gradient(125.19deg, rgba(208, 208, 242, 0) 48.74%, rgba(223, 223, 252, 0.6) 98.12%),
linear-gradient(312.62deg, rgba(105, 124, 159, 0) 81.16%, rgba(255, 255, 255, 0.72) 99.61%);
mask-image: radial-gradient(circle at center, transparent 60%, black 100%);
}

虽然效果不是非常理想,但是至少模拟出了类似的效果,将其移至元素上方即可。

方法六:background-clip

最后,我找到了background-clip方法,background-clip方法设置元素的背景(背景图片或颜色)是否延伸到边框下面。它的部分取值和 box-sizing 类似。其中,

  • background-clip: border-box 表示设置的背景 background-image 将延伸至边框
  • background-clip: content-box 表示设置的背景 background-image 被裁剪至内容区(content box)外沿

具体的效果示例可见MDN

重要的是,这个方法可以设置多个参数,用以对应多个background参数,也就是说,我们可以在background-image属性中,设置四层背景,第四层背景(也就是最下方的背景)是要显示的子元素的背景色,第二三层背景则是两个构建边框的渐变色,第一层背景(也就是最上方的背景)也是要显示的子元素的背景色,用于遮挡住二三层的渐变色。为了使二三层的渐变色边框能够显露出来,将二三层边框的background-clip参数设置为border-box,而第一层背景的background-clip属性设置为content-box这样第一层背景就只遮挡住了content-box部分的内容,而将border部分的内容显露出现,正好形成了一个边框,并叠加在底层元素的上方。

1
2
3
4
5
6
7
8
9
10
11
12
13
.background-clip-use{
width: 200px;
height: 100px;
border: solid 2px transparent;
border-radius: 50px 0;
background-image:
linear-gradient(100.9deg, #F3F8FF -1.03%, #D7E1EE 37.46%, #A6B4FE 96.14%),
linear-gradient(125.19deg, rgba(28, 208, 242, 0) 48.74%, rgba(23, 223, 252, 0.6) 98.12%),
linear-gradient(312.62deg, rgba(105, 124, 159, 0) 81.16%, rgba(255, 25, 255, 0.72) 99.61%),
linear-gradient(100.9deg, #F3F8FF -1.03%, #D7E1EE 37.46%, #A6B4FE 96.14%);
background-origin: border-box;
background-clip: content-box, border-box, border-box, border-box;
}

裁剪得到的边框如下所示(该情况下去掉了最下方的背景,使得边框单独展示):

添加上最底层的背景后得到了想要的结果,如下图所示

方法七:复制为SVG

另外的开发过程中,对于这类复杂背景,可以直接从figma设计稿中选中图形,右键复制为svg或者png,导入到项目的静态资源中,直接使用url()设置为背景图更加的便捷。


Reference

巧妙实现带圆角的渐变边框

不要图片?CSS实现圆角边框渐变色+背景透明


实现多个渐变色叠加的边框
http://starnight.top/2024/07/29/实现多个渐变色叠加的边框/
作者
Cardy Xie
发布于
2024年7月29日
许可协议