Clipping和Masking 何时使用
前面花了很长的篇幅在《探索CSS Masking模块:Clipping》和《探索CSS Masking模块:Masking》两文中分两部分详细介绍了CSS Masking Module Level 1中的Clipping和Masking的基础知识和相关特性,并且使用一些简单的小示例向大家演示了Clipping和Masking如何使用。记得在介绍Clipping一文中,抛出实际项目中的一个案例,实现一个类似下图镂空的效果:
如果是你,你会怎么做呢?
常规的CSS方法
我写了个小示例,尝试着使用了不同的几种方法来做上面的效果:
分别采用了 box-shadow
、 border
和 radial-gradient
。虽然这几种方式都能实现想要的效果,但每种方式都有其局限性:
box-shadow
和boder
对于不规则图形的镂空,实现难度较大radial-gradient
配合linear-gradient
以及多背景可以实现一些常见图形的镂空效果,但对于较为复杂的同样是较难实现
另外,这几种方式原里都非常简单,借助一个伪元素::after
或::after
来做:
.box-shadow::after {
content: '';
width: 60px;
height: 60px;
background: rgba(0,0,0,0);
position: absolute;
top: 276px;
right: 2px;
border-radius: 100%;
box-shadow: 0 0 0 99999rem rgba(0,0,0,.65);
}
使用box-shadow
的第四个参数,使用一个较大的阴影来实现半透明区域。
.border::after {
content: '';
width: 60px;
height: 60px;
background: rgba(0,0,0,0);
position: absolute;
top: -222px;
right: -500px;
border-radius: 100%;
border: 500px solid rgba(0,0,0,.65);
}
border
和box-shadow
类似,不同的是采用了一个很粗的边框来实现半透明区域。这两种方式都会让伪元素溢出容器,所以需要在容器上设置overflow:hidden
。
再来看radial-gradient
的实现方式:
.radial-gradient::after {
content: '';
background: radial-gradient(circle at 368px 308px, transparent, transparent 30px, rgba(0,0,0,.65) 30px, rgba(0,0,0,.65) 100%);
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
相对而言,radial-radient
灵活性更好,但要掌握如何使用渐变来绘制图形,这就需要你对CSS的渐变相关的知识有较深的了解。如果你对这方面感兴趣的话,你可以阅读下面几篇文章:
- CSS Gradient
- 再说CSS线性渐变
- 再说CSS径向渐变
- 为什么要使用
repeating-linear-gradient
- CSS秘密花园:条纹背景
- 你真的理解CSS的
linear-gradient
? - 一个HTML元素和五个CSS属性的魔力
- 使用CSS渐变绘图
- CSS3 Patterns, Explained
- CSS3 Patterns Gallery
似乎这个跟我们今天要聊的主题没有太大关系一样,事实只是拿这个示例做为一个引子,做一个抛砖引玉的效果。
Clipping 和 Masking能做什么
从某种意义上来说,Clipping和Masking都可以让元素某些部分可见和不可见。简单地说:
Clipping用于外切(被切的部分不可见);Masking用于内切(内部可见),对于Masking而言一切取决于遮罩图形。
两者区别之处:
- 剪切需要一个剪切路径,剪切路径可以是一个闭合矢量路径、形状或多边形;剪切路径是一个区域,该区域内部的所有内容都可以显示出来,外部的所有内容将被剪切掉,在页面上不可见
- 遮罩需要一个高亮或Alpha遮罩层,将源和遮罩层合在一起会创建一个缓冲区域,在合层阶段之前,亮度和Alpha遮罩会影响这个缓冲区的透明度,从而实现完全或部分遮罩源的部分
Clipping 和 Masking何时使用
那么在实际使用当中,Clipping和Masking应该怎么去选择运用场景呢?好比文章开头提到的案例,实现类似上图镂空的效果,是应该使用Clipping呢?还是Masking呢?
从效果上看,是在一个黑色半透明层(比如rgba(0,0,0,.65)
)上挖去一个大约64px x 64px
的圆形,而且这个圆形刚好在对应的Icon位置。对应前面所学的Clipping和Masking相关的知识,要实现这样的一个镂空效果,我们应该使用Masking来实现,因为它是一个内切。
接下来,我们来看怎么使用Masking相关的知识来实现这样的效果。
首先有一个Web页面,好比下图这样的效果:
接着在上面盖了一个层,比如使用一个伪元素实现:
Masking中有两个遮罩模式,高亮模式和Alpha模式:
根据遮罩模式的相关原理,我们需要的遮罩图应该像下面这样的:
不管是Alpha模式还是高亮模式,使用mask
相关属性即可将伪元素所需要的地方进行镂空:
.mask-alpha,
.mask-luminance{
&::after {
mask: radial-gradient(circle at 368px 308px, transparent,transparent 30px, rgba(0, 0, 0, 1) 30px, rgba(0, 0, 0, 1) 100%) no-repeat;
mask-size: 440px 688px;
}
}
你将看到的效果如下:
看上去和文章最开始使用的渐变实现的效果是一样的,只不过将渐变图像换成遮罩图像。或许很多同学会认为这样做,不是把事情变得更复杂了,既然渐变就可以实现,为什么还需要采用遮罩来呢?事实上,采用遮罩还是有其优势之处的。比如,你要的效果是不是一个圆,是其他不规则的图形。那么我们就可以借助SVG或者PNG图来做为遮罩图。还是拿这个为例,我们有一个遮罩图像:
这是一张带有Alpha通道的遮罩图:
如果直接将上面的遮罩图运用于案例中,你会看到的效果如下:
这离我们想要的实际效果相关甚完。就算是我们换过一张图:
能看到镂空效果,但和我们所需还是甚远:
换张大图肯定能达到我们想要的效果,但这又回到以前使用背景图片的年代,即可扩展性,可维护性不好。
接着,我们换过一种思维,采用两张图(即两张遮罩图),比如前面那个带Alpha通道的遮罩图,再配一张全黑或全白的图(使用CSS渐变绘制出来的),再结合Masking的合成计算来达到我们想要的效果,把上面的示例修改一下:
.mask{
background: url('https://static.fedev.cn/sites/default/files/blogs/2019/1905/mask-clip-path-1.png') no-repeat;
background-size: 400px 688px;
position: relative;
&::after {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0,0,0,.65);
mask-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/217233/mask.png'), linear-gradient(to bottom, #fff, #fff);
mask-repeat:no-repeat, repeat;
mask-position: 338px 274px, 0 0;
mask-size: 64px 64px;
mask-composite: exclude;
mask-composite: xor;
}
}
你将看到的效果如下:
@Jamie Coulter在Codepen上使用mask
做了另一个有意思的遮罩效果,效果如下,在区域移动鼠标,能看到清晰的内容:
CSS Maksing除来实现上面这种镂空和探照灯的效果之外,还能实现什么样的效果呢?或者说使用场景?
记得在《Web技巧(06)》一文中向大家展示如何使用CSS的特性来修改Icon图标的颜色,而且其中给大家演示了如何使用mask
来修改图标颜色。
假设我们有一个黑色的图标:
借助CSS的mask
可以很轻易的修改Icon图标的颜色:
既可以实现纯色的Icon,还可以实现渐变色的Icon:
.mask {
mask: url(https://static.fedev.cn/sites/default/files/blogs/2019/1905/icon-bell-black.svg) no-repeat center;
mask-size: cover;
background-color: #f36;
}
.mask-gradient {
mask: url(https://static.fedev.cn/sites/default/files/blogs/2019/1905/icon-bell-black.svg) no-repeat center;
mask-size: cover;
background: linear-gradient(to right, #f36, #de9);
}
在互动项目中,为了营造一些氛围效果,文本会有一些渐变填充的效果。早前实现该效果一般都会使用:
background-image: linear(to right, #f36, #ef9);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
如果背景是图片的话,还可以实现图片填充文本的效果:
有了mask
相关特性之外,也可以实现文本填充的效果,只不过要有较好的纹理或渐变填充,该方法相对较难一些,但可以实现一些其他的效果,比如下面这个示例:
其实,在CSS的mask
中还可以引用SVG的<mask>
元素来作为遮罩源,使用这种技术也可以实现文本填充的效果,只不过目前只有Firefox浏览器才支持。我Fork了@Preethi Sam写的一个示例:
<div class="backdrop">
<p class='text'></p>
</div>
<svg>
<defs>
<mask id="m" >
<rect width="100%" height="100%" fill="white" />
<text x="50%" y="75%" text-anchor="middle">Taitō</text>
</mask >
</defs>
</svg>
CSS代码如下:
.backdrop {
background: linear-gradient(to right, #f36, #90f, #ed0, #0ff, #ad3) center;
width:80vw;
margin: 0 auto;
}
.text {
height:20vw;
margin: 0;
font: bolder 10vw 'Alfa Slab One';
background: linear-gradient(to right,#ad3, #0ff, #ed0, #90f, #f36);
mask-type: luminance;
mask: url("#m");
}
svg{
width: 80vw;
height: 20vw;
}
text{
font:bolder 8vw 'Alfa Slab One';
}
效果如下:
如果需要查看在线Demo的效果,请使用Firefox浏览器点击这里查看。
如果你对文本填充的一些效果感兴趣,可以阅读下面这些教程:
除了上面提到的这些效果之外,还可以实现一些其他的效果,比如底部淡入遮罩效果:
上图的效果来自于 @Fernanda Parisi写的一个Demo
配合CSS的animation
特性,还可以做一些有趣的动效,比如 @Shak Daniel写的这个Demo效果:
在介绍Masking特性的时候,还向大家演示了如何借助mask-border
特性和mask
特性来实现优惠卷的效果:
要是配合多个mask
还可以轻易实现下图这样的效果:
有关于实现这个内凹角更详细的介绍,可以阅读@ANA TUDOR的《Scooped Corners in 2018》一文。中文介绍可以点击这里。
前面主要聊了一下,CSS的Masking可运用的场景,接着我们来简单的聊聊Clipping可运用的场景。从Clipping一文中,我们知道CSS的clip-path
可以绘制一些基本图形或者较为复杂的多边形,比如Clippy提供的这些效果:
也就是说,对于一些需要不规则图形的场景之下,都可以使用Clipping相关的特切,比如Clipping一文中演示的示例:
除了这些效果之外,还可以实现其他的一些效果,比如结合SVG的<clipPath>
也可以轻易实现文本填充的效果,比如下面这个效果:
你也可以发挥你的创意,像 @Christopher Kirk-Nielsen 一样使用clip-path
整出类似卡通图的动效:
接着再来看几个实际项目中会用到的,比如下图这样的效果:
使用 clip-path
就可以很容易实现:
.notch {
--notchSize: 2em;
clip-path:
polygon(
0% var(--notchSize),
var(--notchSize) 0%,
calc(100% - var(--notchSize)) 0%,
100% var(--notchSize),
100% calc(100% - var(--notchSize)),
calc(100% - var(--notchSize)) 100%,
var(--notchSize) 100%,
0% calc(100% - var(--notchSize))
);
}
如果你的产品说我需要用户的头像是不规则的,那clip-path
的优势就来了:
更有意思的是,在CSS Shapes中也会用到clip-path
属性,可以让你实现很多不规则的Web布局效果,比如:
还可以配合CSS的offset-path
特性实现一些路径动效(CSS Motion Path)。比如 @一丝姐姐写的 支付宝芝麻信用动画效果:
小结
到这为止,有关于CSS Masking Module Level1相关的特性就算是介绍完了,有关于该特性中涉及理论知识部分主要在《探索CSS Masking模块:Masking》和《探索CSS Masking模块:Clipping》中花了较长的篇幅阐述完了。为了验证CSS Masking特性的可用性,从实际项目进行展开,并且深度扩展开,探讨了CSS中Clipping和Masking在实际生产中的一些使用场景。最后希望这篇文章对大家有所帮助,希望大家能尝试着将该特性用于生产中,提高更可用性。如果您在这方面有相关经验和建议,欢迎在下面的评论中一起分享。