使用 z-index 堆叠伪元素

stacking pseudo-elements with z-index

我在使用 CSS z-index 正确堆叠 div 时遇到问题。在我的代码中,如果我将 .nose::before.nose::after 设置为 z-index: -1,它会将两个 div 放在堆栈的最后面。但是,我只是把这些divs 坐到了.nose 后面div。这是我的代码:

*, *::after, *::before {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body { height: 100%; }

body {
  background: #44BBA4;
}

.head {
  position: absolute;
  margin: auto;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  height: 375px;
  width: 400px;
  background: #df9e27;
  border-radius: 50%;
  border: 10px solid #000;
}

.head::before, .head::after {
  content: "";
  position: absolute;
  height: 90px;
  width: 90px;
  background: #df9e27;
  border-radius: 50%;
  border: 10px solid #000;
  z-index: -1;
}

.head::before {
  top: -30px;
  left: 40px;
}

.head::after {
  top: -30px;
  right: 40px;
}

.eye {
  position: absolute;
  top: 150px;
  height: 25px;
  width: 25px;
  background: #000;
  border-radius: 50%;
}

.eye.left {
  left: 90px;
}

.eye.right {
  right: 90px;
}

.eye::before {
  content: "";
  position: absolute;
  top: -50px;
  left: -37px;
  height: 100px;
  width: 100px;
  border-radius: 50%;
  border: 12px solid transparent;
  border-top: 12px solid #000;
}

.nose {
  position: absolute;
  margin: auto;
  right: 0;
  left: 0;
  bottom: 130px;
  height: 30px;
  width: 30px;
  background: #000;
  border-radius: 50%;
}

.nose::before, .nose::after {
  content: "";
  position: absolute;
  height: 68px;
  width: 73px;
  background: #fff;
  border-radius: 50%;
  border: 10px solid #000;
  z-index: -1;
}
<div class="head">
  <div class="eye left"></div>
  <div class="eye right"></div>
  
  <div class="nose"></div>
</div>

简而言之: 在你的 head 元素上设置 z-index。将耳朵移出头部元素。

原因如下。

z-index 有堆叠上下文。这些上下文中的每一个都有一个根元素(只是任何 html 元素)。现在,要成为根元素,它必须符合以下任一规则:

  • 成为<html>元素
  • static以外的位置和auto以外的z-index
  • 不透明度小于 1

所以默认的堆叠上下文是以 <html> 元素为根。

一旦元素在范围内(换句话说,根元素的 child),它只能相对于范围内的元素定位。

将其视为嵌套列表。

这里的 Wrap 是一个根元素,因为它的位置设置为 relative 并且 z-index 设置为 1。它的所有 children 现在都在一个以 Wrap 为根的堆叠范围内.

因此,就像在嵌套列表中一样,特定元素的 children 不能出现在其根之前。例如,Child2 不能出现在 Wrap 之前,因为它在其中。但它可以出现在 Child1.

之前

现在,在您的情况下,结构如下:

注意 head 不是根,因为它不符合成为一个的规则(定位元素也必须有 z-index 除了 auto)。因此,当您将 -1 的 z-index 分配给 Nose::before 和 ::after you get this:

元素一直位于 Head 后面,因为它们在相同的堆叠范围内。但是它们出现在Head::before之上,因为当元素具有相同的z-index时,它们是按照在html.

中出现的顺序堆叠的

现在,为了防止头children出现在它后面,你必须给它加上z-index。这将使它成为新堆叠范围的根元素。

但这又产生了另一个问题。现在耳朵位于头顶。这不可能单独使用 css 来解决,因为它们在头部的堆叠范围内。并且 root 始终位于其每个 children.

之后

要解决这个问题,你必须把耳朵从头上移开。因此,这意味着您将无法再使用伪元素(之前和之后)。我建议在头部外部创建耳朵元素,并将所有内容包裹在其他元素(名为熊?)中,并具有相对位置。如果您仍想相对于头部定位耳朵,则需要包装器。

答案主要受 this article 启发。