使用纯CSS实现弹出框下的遮罩效果

9

我可以通过给任何

添加一个类名turnIntoOverlay,将其转换为弹出框。 (参见JSFiddle)

.turnIntoOverlay {
    position: fixed;
    background-color: white;
    top: 60px;
    max-width: 680px;
    z-index: 80;
    border: 6px solid #BBB;
    box-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
    max-height: 800px;
    overflow: auto;
    padding:10px;
}

现在当弹出窗口显示时,我还想创建一个遮罩层(或蒙版),使其覆盖在弹出框下面的其他页面元素上。为了创建这个遮罩层,我采用了纯CSS方法使用伪类选择器,以便在弹出框(一个turnIntoOverlay元素)可见时简单地显示/隐藏遮罩层。我添加了以下CSS:
.turnIntoOverlay:after {
    content: "";
    background-color: whitesmoke;
    position: fixed;
    width: 100%;
    height: 100%;
    z-index: -1;
    opacity: 0.5;
    top: 0;
    left: 0;
}

除了弹出窗口上的蒙版即使我将 z-index 设置低于弹出窗口时,一切都很好。令人惊讶的是,它只在 z-index=-1 时起作用。你能建议如何纠正这个问题吗?
请查看这里的 JSFiddle

你是如何将类turnIntoOverlay添加到<div/>中的? - Linus Caldwell
有时候客户端通过JavaScript实现,有时候默认就存在。 - Rajat Gupta
我明白了。如果您通过JavaScript添加类,为什么不直接使用全局<div id="overlay"/>,并在添加.turnIntoOverlay的同时附加一个.show或其他类到#overlay上呢?我认为这会大大简化事情。 - Linus Caldwell
正如我所说,有时候它是通过JavaScript添加的,有时候它默认存在于页面上或作为Ajax响应的一部分接收。我曾经考虑过使用JavaScript方法而不是CSS方法,但那会使事情变得太复杂了。 - Rajat Gupta
你看到任何问题吗?你想对Gareth的解决方案发表评论吗? - Rajat Gupta
不,如果您可以接受覆盖 background-color 并且不需要 border 具有所需的颜色,则无需更改 HTML 代码即可完美解决问题。 - Linus Caldwell
3个回答

5
问题在于堆叠上下文。除非父元素不在堆叠上下文中,否则:after内容不能在其父元素下方。 z-index:-1有效是因为它是一个特殊情况,并且优先于父级内容。这就是为什么它不影响文本,但会影响背景和边框。请参见堆叠上下文列表。您的:after { z-index: -1 }在列表中排名第2。
您唯一的选择是使用额外的包装器:
<div class="turnIntoOverlay"><div>this div is convertible to pop up!<input/></div></div>

将当前的样式从.turnIntoOverlay移动到.turnIntoOverlay > div,并将叠加层应用于外部div,并使用正值z-index
.turnIntoOverlay:after {
    z-index: 1;
}

这里有一个演示

不幸的是,IE8及以下版本存在缺陷。此外,它们不支持opacity,使用-ms-filter在没有布局的元素上(如伪类:before:after)也无法生效。


当然,如果你已经使用了额外的包装器,你可以直接给另一个包装器设置背景颜色,这样就不需要使用“:after”了:
.turnIntoOverlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: skyblue; /* for old browsers */
    background-color: rgba(135, 206, 235, 0.4);
}

与伪类方法相比,这种方法包含了对IE8及以下版本的一些修复。可以通过使用应用于IE的透明png图像来进一步改善。这样,在每个浏览器中看起来几乎相同(我想在IE6之后是这样的)。 这里有一个演示

谢谢Linus,虽然你提出的解决方案可行,但我不喜欢在div.turnIntoOverlay内添加额外的div。此外,我需要确保在div.turnIntoOverlay内只放置1个div。@Gareth的解决方案似乎可以克服这些情况。 - Rajat Gupta

2
我的解决方案是同时使用 :before:after 来解决你的问题:
.turnIntoOverlay {
    position: fixed;
    background-color: white;
    top: 60px;
    max-width: 680px;
    border: 6px solid #BBB;
    box-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
    max-height: 800px;
    overflow: auto;
    padding:10px;
    z-index: 80;
}

.turnIntoOverlay:before {
    content: "";
    background-color: skyblue;
    position: fixed;
    width: 100%;
    height: 100%;
    z-index: -1;
    opacity: 0.4;
    top: 0;
    left: 0;
}

.turnIntoOverlay:after{
    position: absolute; 
    width: 100%;
    height: 100%;
    top: 0; 
    left: 0;
    background-color: white;
    z-index: -1;
    content: "";
}

JSFiddle


你对这种CSS遮罩效果的跨浏览器兼容性有什么看法吗? - Rajat Gupta
1
这适用于所有使用 :after 的解决方案:一个问题是 IE8 及以下版本不支持 opacity。你可以使用 -ms-filter,但遗憾的是 IE 只对具有布局的元素应用过滤器,而伪元素 :after 没有布局。 - Linus Caldwell
@Gareth Cornish:这个解决方案存在问题。当覆盖层div上有滚动条时,对于其中溢出的标记,滚动条是可见的,但无法通过鼠标按下+移动来滚动,但可以使用鼠标滚轮。请参见JSfiddle- http://jsfiddle.net/CVvhF/18/。 - Rajat Gupta
你有没有解决这个问题的方法? - Rajat Gupta

0

我从 .turnIntoOverlay 中移除了 position: fixed,现在它可以正常工作了。


谢谢,但这对我来说不是一个解决方案,因为我需要固定定位。 - Rajat Gupta
除了它不再是一个弹出窗口。 - Gareth Cornish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接