几种通过阴影来弱化背景的CSS方法
很多时候,我们需要一层半透明的遮罩层来把后面的一些整体调暗,以便凸显某个特定的UI元素,引导用户关注。比如下图。这个效果最常见的实现方法就是增加一个额外的HTML元素用于遮挡背景,然后为它添加一些样式:
HTML常规方案
.overlay{/* 用于遮挡背景 */
position:fixed;
top:0;right:0;bottom:0;left:0;
background:rgba(0,0,0,.8);
}
.lightbox{/* 需要吸引用户注意的元素 */
position:absolute;
z-index:1;
}
这个方法稳定可靠,但要增加一个额外的HTML元素,这意味着该效果无法由CSS单独实现。这不是一个很严重的问题,但对我们来说又的确是个麻烦事。不过我们有其他的方法来做。
伪元素方案
我们可以用伪元素来消除额外的HTML元素,比如:
body.dimmed::before{
position:fixed;
top:0;right:0;bottom:0;left:0;
z-index:-1;
background:rgba(0,0,0,.8);
}
这个办法的确有一定改善,因为我们直接在CSS层面使用这个效果。不过问题来了,这个方法的可移移植性还不够好,因为<body>
元素上可能有其他需求已经占用了::before
元素;而且在这个效果时,我们往往还需要一点JavaScript来给<body>
添加dimmed
这个类。
如果遮罩层交给这个元素自己的::before
伪元素来实现,就可以弥补这些不足了。给伪元素设置z-index:-1;
,就可以让它出现在元素的背后,尽管这解决了可移植性的问题。但无法对遮罩层的Z轴进行细化控制。它可能会出现在这个元素之后,但也可能出现在这个元素的父元素之后。
这个方法还有一个问题,伪元素无法绑定独立的JavaScript事件处理函数。当遮罩层由一个独立的元素来实现时,我们可以给它绑定事件处理函数。当弹出层自己的伪元素来实现遮罩时,就需要判断用户到底点了弹出层还是遮罩层,这就变得相当辣手了。
box-shadow方案
对于简单的应用场景来说,我们可以利用box-shadow
来达到调暗背景的效果:box-shadow
的扩张参数可以把元素的投影向各个方向延伸放大。具体做法就是生成一个巨大的投影,不偏移也不模糊,简单地模拟出遮罩层的效果:
box-shadow:0 0 0 999px rgba(0,0,0,.8);
这个初步的解决方案有一个明显的问题,就是无法在较大的屏幕分辨率(>2000px)下正常工作。我们要么加大数字来缓解这个问题,要么换用视口单位来一劳永逸解决它。
这里我们用到了最适合的vmax单位。1vmax相当于1vw个1vh两者中的较大值。100vw等于这个视口的宽度,100vh就是视口的高度。因此,满足我们需求的最小值就是50vmax。
box-shadow:0 0 0 50vmax rgba(0,0,0,.8);
这个技巧非常简洁易用,但它存在两个非常严重的问题,从而制约了其使用场景:
第一,由于遮罩层的尺寸与视口相关,而不是与页面相关,当我们滚动页面时,遮罩层的边缘就露出来了,除非给它加上positon:fixed;
这个样式,或者页面并没有长到需要滚动的程度。
第二,当一个独立的元素(或伪元素)来实现遮罩层时,这个遮罩层不仅可以从视觉上把用户的注意力引导到关键元素上,还可以放置用户与页面的其他部分发生交互,因为遮罩层会捕获所有的指针事件。box-shadow
并没有这个能力,因此它只能在视觉上起到引导注意力的作用,却无法阻止鼠标交互。这一点是否可以接受,取决于你的具体需求。
box-shadow方案(不完全兼容)
如果你想引导用户关注一个元素就是一个模态的<dialog>
元素(它可以用showModal()
方法显示出来),那么根据浏览器的默认样式,它会自带一个遮罩层。借助::backdrop
伪元素,这个原生的遮罩层可以设置样式的:
dialog::backdrop{
background:rgba(0,0,0,.8);
}
不过可惜的是,在文章发表时这个兼容性还很不友好。