css渐变圆角边框
需求功能
需要实现一个渐变圆角边框的 div,且不仅边框是渐变色,要求 div 内部也是另一种带透明度的渐变色。(注意,下面所有示例都基于 css 属性 box-sizing: border-box)
实现方案
方案 1——双层 div 叠加
能想到最直接的方案就是两层 div 叠加,外层 div 较大,负责边框渐变色,内层 div 较小,负责内部区域颜色。但是由于是两层 div 叠加,内层要实现的渐变色如果没有透明度,是没问题的;若是内层 div 要实现的渐变色带有透明度,外层颜色就会透过透明的内层显示出来,这个方案就不适用了。
内层无透明度,正常显示
内层有透明度,底色透出来了
<div class="test1">
<div class="test1-inner"></div>
</div>
<style>
.test1 {
width: 200px;
height: 100px;
background-image: linear-gradient(to right, #9c20aa, #fb3570);
border-radius: 6px;
position: relative;
}
.test1-inner {
/* 内比外小,尺寸差为边框宽度的两倍 */
width: 190px;
height: 90px;
/* 内层居中 */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* 内层渐变色,透明度必需为1,否则外层色露出,故不适用内层有渐变色的渐变 */
background-image: linear-gradient(
to right,
rgba(128, 128, 128, 1),
rgba(0, 0, 0, 1)
);
/* 内层圆角 */
border-radius: 6px;
}
</style>
方案 2——边框图片
使用 css 边框图片属性 border-image 实现,不需要嵌套 div 实现,更直观,也支持带有透明度的背景色,但缺点是不支持圆角设置。
<div class="test2"></div>
<style>
.test2 {
width: 200px;
height: 100px;
background: linear-gradient(
to right,
rgba(128, 128, 128, 0.5),
rgba(0, 0, 0, 0)
);
border: 5px solid;
/* 背景图片 */
border-image-source: linear-gradient(to right, #9c20aa, #fb3570);
/* 背景图片九宫格切割参数,决定背景图片在边框上的展示范围 */
/* 由于我们是渐变色,切割参数设置为非0值即可,因为切割区域大小,不影响渐变色的展示 */
border-image-slice: 1;
/* 圆角设置,仅对纯色边框生效,对边框图片属性无效 */
border-radius: 6px;
}
</style>
方案 3——双层背景叠加
与方案 1 原理一样,只不过不再使用两个 div,而是直接使用 css 背景图的多层叠加特性实现。缺点也同方案 1 一样,不支持内层有透明度。
需要特别注意的是,多层背景图片,后书写的在底层,先书写的在顶层。
内层无透明度,正常显示
内层有透明度,底色透出
<div class="test3"></div>
<style>
.test3 {
width: 200px;
height: 100px;
/* 通过 padding 留出边框距离 */
padding: 5px;
/* 两层背景图设置,注意两层间用逗号分隔,顶层依然无法支持带透明的颜色 */
background-image: linear-gradient(
to right,
rgba(128, 128, 128, 1),
rgba(0, 0, 0, 1)
), linear-gradient(to right, #9c20aa, #fb3570);
/* 顶层占用 content-box,底层占用 border-box */
background-clip: content-box, border-box;
border-radius: 6px;
}
</style>
方案 4——css mask
使用 css 的 mask 属性,可以说是最佳实现方案了,可以完美支持边框渐变、中间区域背景带有透明度、边框圆角等所有需求。不过由于还处于推荐候选草案(Candidate Recommendation Draft)阶段,兼容性稍差,IE 浏览器不支持,webkit 内核的浏览器需要增加-webkit-
前缀,一般脚手架已通过 babel 做自动兼容,无需手动添加前缀。不过下面的示例中,还是都添加了。
实现原理:先建立一个 div,为 div 设置圆角和内边距(内边距即最终的边框宽度),并设置为相对位置position: relative
(方便内部伪元素相对该元素定位);再建立一个伪元素使用 mask 来实现圆角渐变的边框,伪元素与外层 div 圆角值及内边距一致即可,伪元素使用绝对定位,这样父元素使用任何布局都不会影响到伪元素。
<div class="test4"></div>
<style>
.test4 {
width: 200px;
height: 100px;
padding: 5px;
border-radius: 6px;
position: relative;
background: linear-gradient(
to right,
rgba(128, 128, 128, 0.5),
rgba(0, 0, 0, 0)
);
}
.test4::before {
content: "";
/* 绝对定位,四个方向值都设置为0,不设宽高,相当于宽高100% */
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* 内边距与圆角值与外部一样,内边距表示边框宽度 */
padding: 5px;
border-radius: 6px;
/* 背景渐变色为边框色 */
background: linear-gradient(to right, #9c20aa, #fb3570) border-box;
/* 设置两层全透明遮罩,上层后绘制,故称为源层,在内边距以内,下层先绘制,故为目标层,在边框以内 */
/* 注意 这里与多层背景先写的 */
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0) border-box;
/* exclude 即排除多层 mask 重叠部分,exclude 仅 firefox 支持 */
mask-composite: exclude;
/* webkit 兼容写法 */
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(
#fff 0 0
) border-box;
/* webkit 支持属性与 firefox 不一致,更像是 Canvas 的 globalCompositeOperation 属性,只是不如 Canvas 中支持的属性多,且个别属性表现行为稍有不一致。*/
/* destination-out 指 目标遮罩与源遮罩重叠部分全部排除,显示为透明,仅保留目标遮罩不重叠部分 */
-webkit-mask-composite: destination-out;
}
</style>
最佳方案中用到了 CSS Mask 属性,可以在另一篇文章——css遮罩mask中详细了解 CSS Mask。
参考资料
Border Gradient with Border Radius
Possible to use border-radius together with a border-image which has a gradient?