昨天有个模块分到我手里了,有个优惠券的组件要封装,公司做前端的好像对CSS都不是很熟(其实就是一群Javaer兼职干前端),估计是用多了React、Bootstrap这种现成的框架(就只知道写组件了),没写过啥基础的CSS。然后有个优惠券的模块分到了我的头上,正好总结总结。
优惠券最主要就是这个锯齿的问题。其实用图片做也完全可以,反正最后那些小图片都会被webpack编码成Base64的DataURL
关于DataURL的内容可以参考RFC2397
不过用图片方式就没有啥挑战性了,那我也没必要写这篇文章记录这个过程。
我们的目的是用纯CSS实现锯齿
一、使用before和after伪元素的border实现
先看一张效果图
先定义一下最基本的html:
这里我们主要关注怎么实现锯齿,内容什么的我就没写,背景颜色也直接放在html里面了。
1 | <div class="sawtooth" style="background:#e24141;width:400px;height:170px;"></div> |
1. 用dotted圆点边框覆盖div
我们的主要思路就是用两排圆点覆盖在div上:
1 | .sawtooth { |
得到下面这样的效果:
2. 微调边框位置
但是由于圆点是顶着div开始的,总感觉不怎么好看,我们把before和after两个伪元素往下移动一点:
1 | .sawtooth:before, .sawtooth:after { |
这样虽然已经出效果了,但是在实际应用中,由于背景色的不同导致,我们border圆点露馅了:
3. 隐藏多余的部分
为了解决这个问题,我们把需要把超出div的部分剪切掉:
1 | .sawtooth { |
因为border的颜色(白色)和背景色(青绿色)不同,导致优惠券看上去很突兀。
对于这个问题,最开始相到的解决办法是让把border设置为transparent
(透明),可惜透明的结果是显示后面div的红色。所以暂时只能用最笨的方法:把border的颜色设置成背景色。
整理以下CSS
1 | .sawtooth { |
二、使用透明背景实现
上面的方法的缺点是,我们需要让border的颜色和背景色一致,才能让我们的优惠券不“露馅”。
所以这次我们就直接用透明的背景。透明的背景当然不是指全透明,全透明那就是没背景了。看一下下面这张图你就知道我们要怎么干了。
哇塞,这么多洞!密集恐惧症患者,看了估计有点闹心。
我们的主要思路是:在这张有这么多洞的网上面盖一张div,把多余的洞遮住,只保留两边有锯齿的洞。
不过使用这种方式我们先要把html中的背景色干掉,只保留宽高:
1 | <div class="sawtooth" style="width:420px;height:170px;"></div> |
1. 用css画出这张网
为了画出这么多的洞,我们要用到radial-gradient
这个渐变函数,不过我们并不需要用到它的渐变功能,只要用它来画透明的圆点就行。
radial-gradient要求IE10及以上的版本的浏览器。
关于radial-gradient的更多详细内容,请参考MDN的文档
1 | .sawtooth{ |
上面简单的三句话就生成了这张网:
也许你看到样式上面的注释会很纳闷,这样就生成了一张网?你把sawtooth类改成下面的样式看一下,估计你就会明白了:
1 | .sawtooth{ |
2. 找一个元素把多余的洞覆盖掉
为了不影响html的整洁性,我们就使用before或after这两个伪元素中的一个来覆盖多余的洞吧。
1 | .sawtooth { |
完成的效果图如下:
3. 让遮罩层下移,让它成为背景
上面的样式还有一点点问题。
当我们网div中加内容的时候:
1 | <div class="sawtooth" style="width:420px;height:170px;"> |
发现它不仅把洞给遮住了,还把我们的内容给遮住了:
出现上面这种现象的原因就是:绝对定位脱离文档流后,会浮在文档的上面。
“我们的内容在地表上,遮罩层却在一楼”
为了解决这个问题,我们还需要加一个样式,让这个遮罩层不再是“遮罩层”,而是在文档下面当做背景。
1 | .sawtooth:before { |
让“遮罩层”到负一楼去。
OK,我们想要的效果有了。
而且不管背景换成什么颜色,我们的“优惠券”都不会“露馅”。
4. 双层背景实现遮罩
使用伪元素实现遮罩除了要使用z-index
改变层级外,代码也显得冗长,我们还可以用双层背景来实现遮罩。为了让两个背景大小不一样我们还要用到background-clip来设置背景的裁剪区域,background-clip
支持四种属性值(text兼容性不好):
下面用将网装背景剪裁区域设置为border-box
,纯色背景裁剪区域设置为padding-box
用来遮罩。
1 | .sawtooth { |
感谢评论区xlf-summer给出解决思路。他最初的思路是用
linear-gradient
实现遮罩背景:
background: border-box radial-gradient(transparent 0, transparent 5px, #e24141 5px), padding-box linear-gradient(#e24141, #e24141);
不过我在实践的时候,发现直接用纯色背景也可以实现效果。
附加:改变形状,生成别样的锯齿
我们可以通过适当修改background的几个参数,将圆形压扁,生成其他形状的锯齿:
1 | .sawtooth { |