用 css3 的 mask + radial-gradient() 制作优惠券
我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情。
概览
最近项目做到优惠券模块,发现 UI 效果图如下:
之前我前端实现上图这种内凹的圆,都是用
:before
或 :after
伪元素选择器弄 2 个圆,背景色设置成红色,通过绝对定位实现的。但这次不行,因为如果你仔细看会发现优惠券的红色背景,从左往右是有渐变效果的,所以如果还是弄两个红色的圆放上去就会“穿帮”。通过查询资料,我最终使用 css3 的 2 个属性:mask
和 radial-gradient()
实现。先把完整代码放前面,如果急着下班只是想简单 cv 可以直接拿走不谢:
<!-- 例 1.1 -->
<div class="coupon-wrap">
<div class="coupon-wrap_inner"></div>
</div>
/* 例 1.2 */
.coupon-wrap {
width: 690px;
height: 200px;
margin: 30px;
background: linear-gradient(-87deg, #ff3939 0%, #ff6b5e 100%);
border-radius: 6px;
padding: 10px;
}
.coupon-wrap_inner {
height: 100%;
background: #ffffff;
border-radius: 6px;
-webkit-mask: radial-gradient(circle at 140px -6%, #0000 20px, #000 0),
radial-gradient(circle at 140px 106%, #0000 20px, #000 0);
-webkit-mask-size: 100% 51%;
-webkit-mask-position: top, bottom;
-webkit-mask-repeat: no-repeat;
}
实现效果如下图:
接下来详细说说实现原理。
mask(遮罩)
对 css3 中 mask
属性的学习可以多注意和 background
属性进行对比,它们有很多相似之处,下面我们来分别看看几个 mask
属性,并准备一个蓝色的矩形用于测试:
<div class="box"></div>
.box {
width: 200px;
height: 100px;
background: #1e80ff;
}
mask-image
/* 例 2.1 */
.box {
/* ... */
-webkit-mask-image: url('./img/logo.svg');
}
请注意,mask 属性目前还未标准化,所以相关属性在 chrome 浏览器中需要添加 -webkit- 前缀才会生效。其浏览器兼容性可见下图:
添加完 mask-image
属性后效果如下:
可以看到原本的蓝色矩形现在只剩下了 logo 区域显示了出来,也就是说作为 mask-image 的图片不透明的地方,可以透过去看到被遮罩的图片,而透明的部分反而会隐藏住被遮罩的图片,其实就是 PS 里的蒙版效果。
logo 默认是 x、 y 轴方向进行了重复平铺。如果我们只想显示 1 个 logo 呢?那就需要用到下面的这个 mask-repeat
属性:
mask-repeat
设置遮罩的重复模式,和 background-repeat
很像,可以接收的值有 repeat-x
或 repeat-y
或是 1 ~ 2 个的 repeat | space | round | no-repeat
,代表 x 轴和 y 轴方向 。如果我们不想让 logo 自动重复,可以添加设置 mask-repeat
为 no-repeat
:
/* 例 2.2 */
.box {
/* ... */
-webkit-mask-image: url('./img/logo.svg');
-webkit-mask-repeat: no-repeat;
}
现在效果如下,为了方便看清 logo 在原本矩形中的相对位置,我把鼠标放在了 <div class="box"></div>
上进行元素审查:
可以看到现在就只有 1 个 logo 了,如果我们想让 logo 居中显示,则可以设置 mask-position
属性:
mask-position
设置遮罩的位置模式,同 background-position
一样可以接收 2 个值,分别作用于 x 轴和 y 轴。值可以是 center | left | top | right | bottom
这种关键字,也可以是百分比 <percentage>
或长度 <length>
,比如 50%
或 200px
。 想让 logo 居中只需添加 mask-position
属性为 center
:
/* 例 2.3 */
.box {
/* ... */
-webkit-mask-image: url('./img/logo.svg');
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
}
现在 logo 就移动到矩形中间位置了:
mask-size
我们可以通过 mask-size
来设置遮罩,也就是 logo 的大小,其值可以是百分比 <percentage>
,或类似 100px
这样的长度 <length>
值,也可以是 cover | contain
这种关键词,同样可以结合 background-size
进行理解。如果我们想让 logo 的大小完全占据整个矩形,可以让 mask-size
的值为 100%
/* 例 2.4 */
.box {
/* ... */
-webkit-mask-image: url('./img/logo.svg');
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
-webkit-mask-size: 100%;
}
合并简写
就像 background
那样, mask
也可以多个属性结合在一起简写,比如例 2.4 就可以简写成:
/* 例 2.5 */
.box {
/* ... */
-webkit-mask: url('./img/logo.svg') center/100% no-repeat;
}
mask
后第 1 个值为 mask-image
的值,第 2 个值为设置 mask-position
,在后面添加 /
代表设置 mask-size
,第 3 个值为设置 mask-repeat
。 其实 mask 还有其它一些属性,比如 mask-mode
、mask-composite
等,但是制作优惠券用不上,就不多做介绍了。
radial-gradient()
了解完 mask
属性,我们再来看看优惠券的需求,就是要想办法弄出上下两张各自有个部分椭圆形为透明的矩形对白色矩形进行遮罩,而这种图片使用 css3 做径向渐变的 radial-gradient()
函数可以直接实现,而且前面我们也说到, mask-image
的值可以是 <radial-gradient()>
:
radial-gradient()
CSS 函数创建的是一个径向渐变图像,得到的是一个 CSS <gradient>
数据类型的对象,是 <image>
的一种。所谓径向,就是从“一个点”向四周的渐变,既然是渐变,那么至少需要定义 2 种颜色节点。语法如下:
radial-gradient(<shape> <size> at <position> , <color-stop-list>, ..., <color-stop-list>)
下面对各个参数值做个解释:
参数值
shape
定义渐变的形状,默认是椭圆(ellipse
),也可以指定为圆(circle
);
size
设置渐变的半径大小,值可以是
closest-side
:半径为从圆心到最近的边;closest-corner
:半径为从圆心到最近的角;farthest-side
:半径为从圆心到最远的边;farthest-corner
:半径为从圆心到最远的角。
position
定义渐变的圆心,默认是 center center
,和 mask-position
一样也可以是 left | top | right | bottom
这种关键字,或是百分比 <percentage>
或长度 <length>
。
color-stop-list
用于指定渐变的起止颜色,<color-stop-list>
表示多个 <color-stop>
的集合,而 <color-stop>
表示颜色断点。比如 background-image: linear-gradient(red 10%, yellow 60%)
中的 red 10%
和 yellow 60%
就属于 <color-stop>
。
示例
我们还是准备一个类名为 box
的矩形 div:
<!-- 例 3.1 -->
<div class="box"></div>
添加样式如下:
/* 例 3.2 */
.box {
width: 300px;
height: 200px;
background-image: radial-gradient(red, yellow);
}
例 3.2 中第 5 行 radial-gradient()
的参数只写了 2 个颜色,意味着其它参数都为默认值,所以效果如下图:
可以看到默认情况下是一个颜色均匀渐变的椭圆。注意,容器的宽高我故意设置成不一样的,让它是一个长方形而不是正方形,才能看出默认条件下的 <shape>
为椭圆。
如果我们给颜色添加上位置信息,让红色为 30%,黄色为 60%:
/* 例 3.3 */
.box {
/* ... */
background-image: radial-gradient(red 30%, yellow 60%);
}
效果图如下,可以看到从 0%(表示虚拟渐变射线的起点) 到 30% 是纯红色,从 30% 到 60% 是红黄渐变,60% 到 100%(表示虚拟渐变线与渐变容器相交的位置) 是纯黄色:
例 3.2 相当于是 background-image: radial-gradient(red 0%, yellow 100%);
我们再来试试设置默认形状为圆并且改变 <position>
的效果,让渐变的起始点的 x 轴坐标为 20%,y 轴坐标为 0:
/* 例 3.4 */
.box {
/* ... */
background-image: radial-gradient(circle at 20% 0, red 30%, yellow 60%);
}
现在的效果如下图:
想要最终变为我们制作优惠券想要的效果,上图红色的圆需要变小,然后透明度变为 0。可以使用 rgba(255, 0, 0, 0)
来表示纯红透明的颜色,其实既然是透明的,颜色也就无所谓了,可以改成 rgba(0, 0, 0, 0)
,再少打几个字可以直接写成 #0000
(注意,css 十六进制颜色设置,透明度设置在色值后位,比如 #00000010
,从 00 ~ FF,一共 256 个梯度),至于大小可以由 20% 改为 20px;为了效果更明显,黄色也可以改为黑色:
/* 例 3.5 */
.box {
/* ... */
background-image: radial-gradient(
circle at 20% 0,
#0000 20px,
#000 60%
);
}
现在效果如下:
作为 mask-image 的图片只有完全透明的部分才会完全挡住被遮罩的图层,所以我们需要将上图中 20% ~ 60% 这半透明的区域变为完全不透明的。实现的方法就是让黑色的位置小于透明的位置,比如 10px,为了简单直接设置为 0:
/* 例 3.6 */
.box {
/* ... */
background-image: radial-gradient(
circle at 20% 0,
#0000 20px,
#000 0
);
}
现在就基本实现了我们想要的效果:
总结
回头去看例 1.2 中我们实现优惠券的代码,其实就是用 radial-gradient()
生成了上下 2 张类似例 3.6 的 <image>
,作为 mask-image
的值,对优惠券里面那个白色矩形做了遮罩而已。
需要注意的有 2 点:
mask
的第一个值也就是mask-image
我们设置了 2 个,上下各一个,所以mask-position
的值也是 2 个,用,
隔开;mask-size
中第 2 值(height)设置为 51%,是为了确保上下 2 张遮罩层的图像之间不会留有缝隙导致“穿帮”。
转载自:https://juejin.cn/post/7140476377119064071