首页 > 解决方案 > 为什么具有 z-index 值的元素不能覆盖其子元素?

问题描述

今天经过几个小时的调试,我很难学会这条规则:

如果父元素的 z-index 为任何值,则无论您如何更改子元素的 CSS,父元素都永远无法覆盖(堆叠在其上)其子元素

我怎样才能从逻辑上理解这种行为?它在规格中吗?

.container {
  width: 600px;
  height: 600px;
  background-color: salmon;
  position: relative;
  z-index: 99;
  padding-top: 10px;
}

h1 {
  background-color: pink;
  position: relative;
  z-index: -1;
  font-family: monospace;
}
<div class="container">
  <h1>1. I can never be covered by parent if my z-index is positive.</h1>
  <h1>2. Even when my z-index is nagative, I still can never be covered if my parent has any z-index at all.</h1>
</div>

父元素上方的负 z-index 子元素

标签: csscss-positionz-index

解决方案


您需要了解两件重要的事情:绘画顺序和堆叠上下文。如果您参考规范,您可以找到元素的绘制方式和时间。

  1. 由具有负 z 索引(不包括 0)的已定位后代形成的堆叠上下文按z 索引顺序(最负值在前)然后是树顺序。

  1. 所有定位的、不透明的或变换的后代,按树顺序属于以下类别:
    1. 所有具有“z-index:auto”或“z-index:0”的定位后代,按树顺序排列。

  1. 由z-index 大于或等于 1的定位后代形成的堆叠上下文,按z-index 顺序(最小优先)然后是树顺序。

从这里可以清楚地看出,我们首先z-index在步骤 (3) 中绘制为负的元素,然后z-index在步骤 (8) 中绘制等于 0 的元素,最后z-index在步骤 (9) 中绘制为正的元素,这是合乎逻辑的。我们还可以阅读规范的另一部分:

每个盒子属于一个堆叠上下文。给定堆叠上下文中的每个盒子都有一个整数堆叠级别,这是它在 z 轴上相对于同一堆叠上下文中其他盒子的位置。具有较高堆栈级别的框总是在具有较低堆栈级别的框之前格式化。盒子可能有负的堆栈级别。在堆叠上下文中具有相同堆叠级别的框根据文档树顺序从下到上堆叠。

建立本地堆栈上下文的元素会生成一个具有两个堆栈级别的框:一个用于它创建的堆栈上下文(始终为 0),另一个用于它所属的堆栈上下文(由 z-index 属性给出)。


要了解何时绘制每个元素,您需要知道它的堆叠上下文及其在此堆叠上下文中的堆叠级别z-index(由 定义)。您还需要知道该元素是否建立了堆叠上下文。这是棘手的部分,因为设置z-index会这样做:

对于定位框,z-index 属性指定:

  1. 当前堆栈上下文中盒子的堆栈级别。
  2. 盒子是否建立堆叠上下文

值具有以下含义:

<integer>

这个整数是当前堆叠上下文中生成的盒子的堆叠级别。该框还建立了一个新的堆叠上下文

auto

生成的box在当前stacking context中的stack level为0。box不会建立新的stacking context,除非它是根元素。


现在我们拥有所有信息,可以更好地了解每个案例。如果父元素的z-index值不是auto,那么它将创建一个堆叠上下文,因此子元素将被绘制在它们z-index的内部(负或正)。z-index子元素的 将简单地告诉我们父元素内的绘画顺序(这涵盖了您的第二点)

现在,如果只有子元素有一个正数z-index并且我们没有在父元素上设置任何内容,那么考虑到绘制顺序,子元素将稍后绘制(在步骤(9)中),而父元素将在步骤(8)中绘制。在上面绘制父元素的唯一合乎逻辑的方法是增加z-index,但是这样做会使我们陷入之前的情况,即父元素将建立堆叠上下文,子元素将属于它。

为子元素设置正数时,无法将父元素置于子元素之上。如果我们将 a 设置为不同于(正或负)的父元素,也没有办法让父元素高于子元素。1 z-indexz-indexauto

我们可以在其父元素下方有一个子元素的唯一情况是z-index在子元素上设置一个负数并将父元素保持在z-index: auto,因此这不会创建堆叠上下文并且按照绘制顺序将首先绘制子元素。


除此之外z-index,还有其他创建堆叠上下文的属性。如果您遇到预期的堆叠顺序,您还需要考虑这些属性,以查看是否创建了堆叠上下文。


我们可以从上面得出一些重要的事实:

  1. 堆叠上下文可以包含在其他堆叠上下文中,并共同创建堆叠上下文的层次结构。
  2. 每个堆叠上下文完全独立于其兄弟元素:处理堆叠时只考虑后代元素。
  3. 每个堆叠上下文都是自包含的:在元素的内容被堆叠之后,整个元素被认为是父堆叠上下文的堆叠顺序。参考

1:如果我们考虑使用 3D 变换,会有一些 hacky 方法。

一个元素位于其父元素之下的示例,即使该元素已z-index指定。

.box {
  position:relative;
  z-index:0;
  height:80px;
  background:blue;
  transform-style: preserve-3d; /* This is important */
}
.box > div {
  margin:0 50px;
  height:100px;
  background:red; 
  z-index:-1; /* this will do nothing */
  transform:translateZ(-1px); /* this will do the magic */
}
<div class="box">
  <div></div>
</div>

另一个例子,我们可以在另一个堆叠上下文中的两个元素之间放置一个元素:

.box {
  position: relative;
  z-index: 0;
  height: 80px;
  background: blue;
}

.box>div {
  margin: 0 50px;
  height: 100px;
  background: red;
  z-index: 5;
  transform: translateZ(2px);
}

.outside {
  height: 50px;
  background: green;
  margin: -10px 40px;
  transform: translateZ(1px);
}

body {
  transform-style: preserve-3d;
}
<div class="box">
  <div></div>
</div>

<div class="outside"></div>

我们也可以有一些疯狂的堆叠顺序,如下所示:

.box {
  width: 100px;
  height: 100px;
  position: absolute;
}

body {
  transform-style: preserve-3d;
}
<div class="box" style="top:100px;left:50px;background:red;"></div>
<div class="box" style="top: 50px;left: 115px;background:blue;"></div>
<div class="box" style="top: 101px;left: 170px;background:green;"></div>
<div class="box" style="top: 175px;left: 115px;background:purple;transform: rotateY(-1deg);"></div>

CSS 循环堆叠上下文

我们应该注意,使用这种hack可能会产生一些副作用,因为transform-style,perspective并且transform会影响position:absolute/fixedelement. 相关:父级 CSS-Filter 中断子级定位


推荐阅读