上图是“QQ截图”选择区域时的画面,能够看到除了中间框选的部分,其余区域被一层半透明层覆盖(backdrop),这种效果不知道专业叫法,这里称呼它“镂空遮盖层”。实际业务需求中却是很少见,比较常见的是“页面上的新手引导”,“视频网站的关灯模式”等用到这种效果,通用简单的作法是将内容元素的z-index
设置大于遮盖层的,使该元素显示在遮盖层上面。接下来分享下其余的方法,可能对某些特殊场景有用。网站
如下介绍的方法有:经过多个DIV
拼接,单个DIV
利用CSS的属性border
, outline
, box-shadow
和混合模式mix-blend-mode
来实现,下面分别从视觉和动做来讲明。spa
首先,先用样式实现内容上覆盖一层半透明遮盖,其中某个区域镂空。.net
最原始的方法,围着镂空区域拼接4个div
,拼接的方式不少,好比上面的图中用了不一样颜色来表示4个div
。3d
<div class="box"> <div class="text"></div> <div class="item-1"></div> <div class="item-2"></div> <div class="item-3"></div> <div class="item-4"></div> </div> <style> .item-1, .item-2, .item-3, .item-4 { position: absolute; } .item-1 { top: 0; left: 0; background: rgba(0, 0, 0, 0.5); width: 450; height: 100px; } .item-2 { top: 0; left: 450; right: 0; height: 300px; background: rgba(0, 0, 0, 0.5); } .item-3 { top: 300px; left: 150px; bottom: 0; right: 0; background: rgba(0, 0, 0, 0.5); } .item-4 { top:100px; left: 0; bottom: 0; width: 150px; background: rgba(0, 0, 0, 0.5); } </style>
实例:https://jsfiddle.net/0ast5u2j/code
优势是兼容性好,缺点是要用多个DOM元素去构造遮盖层,计算麻烦,而且镂空区域只能是矩形。视频
盒模型包括了content
和border
,能够用content
表示镂空区域,用border
表示遮盖层,而且经过border-width
来定位镂空区域的位置。和上面的方法有类似之处。blog
<div class="box"> <div class="text"></div> <div class="rect-border"></div> </div> <style> .rect-border { position: fixed; top: 0; left: 0; width: 300px; height: 200px; border-style: solid; border-color: rgba(0, 0, 0, 0.5); border-top-width: 100px; border-right-width: calc(100vw - 450px); border-bottom-width: calc(100vh - 300px); border-left-width: 150px; } </style>
实例:https://jsfiddle.net/708vngj1/事件
用这种方法须要计算,有些状况还须要用到JS,而且镂空区域只能是矩形(固然在不使用渐变的状况下)。图片
outline
不占据空间,不影响自己元素和其余元素,能够经过对它设置足够大的值来做为遮盖层。ip
<div class="box"> <div class="text"></div> <div class="rect-outline"></div> </div> <style> .rect-outline { position: absolute; left: 150px; top: 100px; width: 300px; height: 200px; outline: 3000px solid rgba(0, 0, 0, 0.5); }
实例:https://jsfiddle.net/rujLkg78/
优势简单方便,但镂空区域一样只能是矩形。
与outline
相似,box-shadow
一样不影响元素的大小位置。
<div class="box"> <div class="text"></div> <div class="rect-shadow"></div> </div> <style> .rect-shadow { position: absolute; left: 150px; top: 100px; width: 300px; height: 200px; border-radius: 10px; box-shadow: 0 0 0 3000px rgba(0, 0, 0, 0.5); } </style>
实例:https://jsfiddle.net/8561js9L/
比上面一种方法好的地方是元素设置border-radius
是有效的,因此镂空区域能够是圆角矩形、椭圆、圆形等。
这是在网站https://momodel.cn/ 上看到的,利用混合模式,可使元素与父元素叠加部分透明,摆脱了单个元素限制,使镂空区域能够更自由,作更复杂的图形,好比对话气泡框。
<div class="box"> <div class="text"></div> <div class="overlay"> <div class="spoltlight"> </div> </div> </div> <style> .overlay { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 99999; background-color: rgba(0, 0, 0, 0.5); mix-blend-mode: hard-light; pointer-events: auto; } .spoltlight { position: absolute; left: 150px; top: 100px; width: 300px; height: 200px; border-radius: 10px; background-color: gray; } .spoltlight::after { content: ""; position: absolute; top: 100%; right: 50px; border: 15px solid transparent; border-top-color: gray; } </style>
实例:https://jsfiddle.net/bxjo306z/
其余好比使用Canvas
和SVG
比较麻烦,就不过多介绍了。
Canvas实例:https://jsfiddle.net/3dbcvLp2/
SVG实例:https://jsfiddle.net/6wvdja2h/
不少场景下,还须要对镂空区域下的DOM进行点击、选择等操做。
用DIV拼接的方法,镂空区域原本就是空的,因此能够直接对下面的DOM操做。
其余方法,由于有真实DOM覆盖在内容上面,因此就要用到pointer-events:none
,这样鼠标事件能够“穿透”该元素做用于下面的内容上。
大多数场景须要阻止操做遮盖部分下面的DOM,只对镂空部分进行“穿透”,因此不能直接对镂空遮盖层设置pointer-events:none
,应该在鼠标移动到镂空区域时设置pointer-events:none
,离开镂空区域设置pointer-events:auto
。注意的是不能在镂空遮盖层上监听mosuemove
,由于当它被设置为pointer-events:none
时,就没法监听了。
https://jsfiddle.net/02e64ndr/
对于outline和box-shadow,由于它们自己就不占据空间,鼠标事件对它们是没有效果的,自带“穿透”效果,因此除了要对镂空遮罩层设置pointer-events:none
,还须要再覆盖一层透明的遮盖层,一样监听父级容器的mousemove
事件,动态的对该透明层设置pointer-events
https://jsfiddle.net/4dfagcmr/
混合模式的方法,原觉得经过监听镂空元素的mouseenter
和mouseleave
来控制pointer-events
就能够了,但一样当pointer-events:none
时没法监听鼠标事件,因此也只能经过鼠标坐标来判断。
https://jsfiddle.net/c1aoe0dg/
某些场景下,如仿Snipaste截图效果,须要对遮盖层下的全部元素监听鼠标进出事件,这时候对整个镂空遮罩层设置pointer-events:none
就好了。
语焉不详,敬请谅解。