为什么具有 z-index 值的元素不能覆盖其子元素?
Why can't an element with a z-index value cover its child?
今天经过几个小时的调试,我艰难地学会了这条规则:
无论您如何更改子元素的 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>
The z-index CSS property sets the z-order of a positioned element and its descendants or flex items.
这里有一些来自 another Whosebug article 的关于 children vs 后代的额外逻辑。
考虑这一点的一个好方法是每个 parent 都包含自己的堆栈上下文。同级元素共享 parent 的堆叠顺序,因此可能会相互重叠。
A child 元素总是根据它的 parent 获取堆叠上下文。因此需要负 z-index 值来推动 child "behind" 其 parent (0) 堆栈上下文。
从 parent 的上下文中删除元素的唯一方法是使用 position: fixed
,因为这实际上会强制它使用 window 作为上下文。
How can I understand this behavior by logic?
对我来说很难从逻辑上理解你的问题。一个parent包含它的children。一个碗可以被另一个碗盖住。但是你不能用碗盖住汤,除非你把汤从碗里拿出来。
z-Index 设置重叠元素的顺序。 parent 不能与其 child 重叠。
恕我直言,这完全合乎逻辑。
您需要了解两件重要的事情:绘画顺序和堆叠上下文。如果您参考 the specification,您可以找到绘制元素的方式和时间。
- Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order (most negative first) then tree order.
- All positioned, opacity or transform descendants, in tree order that fall into the following categories:
- 所有具有 'z-index: auto' 或 'z-index: 0' 的后代,按树顺序排列。
- Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index order (smallest first) then tree order.
由此可见,我们首先在第(3)步绘制负数z-index
的元素,然后在第(8)步绘制z-index
等于0的元素,最后绘制负数z-index
等于0的元素在第 (9) 步为正 z-index
,这是合乎逻辑的。我们还可以在the specification的另一部分阅读:
Each box belongs to one stacking context. Each box in a given stacking context has an integer stack level, which is its position on the z-axis relative to other boxes in the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked bottom-to-top according to document tree order.
要了解何时绘制每个元素,您需要知道此堆栈上下文中的其堆栈上下文和其堆栈级别(已定义通过 z-index
)。您还需要知道该元素是否建立了堆叠上下文。这是棘手的部分,因为设置 z-index
将执行此操作:
For a positioned box, the z-index property specifies:
- The stack level of the box in the current stacking context.
- Whether the box establishes a stacking context
Values have the following meanings:
<integer>
This integer is the stack level of the generated box in the current stacking context. The box also establishes a new stacking context.
auto
The stack level of the generated box in the current stacking context is 0. The box does not establish a new stacking context unless it is the root element.
现在我们掌握了所有信息,可以更好地了解每个案例。如果 parent 元素的 z-index
值不是 auto
,那么它将创建一个堆叠上下文,因此 child 元素将被绘制在任何它们的 z-index
是(负或正)。 child 元素的 z-index
将简单地告诉我们 parent 元素内的绘制顺序 (这涵盖了你的第二点).
现在,如果只有 child 元素具有正 z-index
而我们在 parent 元素上不设置任何内容,那么考虑到绘制顺序, child 将稍后绘制(在步骤(9)中)和步骤(8)中的parent。上面画parent的唯一合乎逻辑的方法是增加z-index
,但是这样做会让我们陷入之前的情况,parent会建立一个堆叠上下文,而child元素将属于它。
当设置 positive 时,无法 在 child 元素上方设置 parent z-index
到 child。如果我们将 z-index
设置为 parent 不同于 auto
(正或负)。1
我们可以在其 parent 下方设置 child 的唯一情况是在 child 元素上设置负数 z-index
并保留 parent 在 z-index: auto
,因此这个不会创建堆叠上下文,并且按照绘制顺序首先绘制 child。
除了z-index
,还有other properties that create a stacking context。如果您面临预期的堆叠顺序,您还需要考虑这些属性,以查看是否创建了堆叠上下文。
我们可以从上面得出的一些重要事实:
- Stacking contexts can be contained in other stacking contexts, and together create a hierarchy of stacking contexts.
- Each stacking context is completely independent of its siblings: only descendant elements are considered when stacking is processed.
- Each stacking context is self-contained: after the element's contents are stacked, the whole element is considered in the stacking order of the parent stacking context. ref
1:如果我们考虑使用 3D 转换,则有一些 hacky 方法。
一个元素位于其 parent 元素之下的示例,即使此元素指定了 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;
transform-style: preserve-3d;
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>
我们应该注意,使用这样的 hack 可能会产生一些副作用,因为 transform-style
、perspective
和 transform
会影响 position:absolute/fixed
元素。相关:
今天经过几个小时的调试,我艰难地学会了这条规则:
无论您如何更改子元素的 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>
The z-index CSS property sets the z-order of a positioned element and its descendants or flex items.
这里有一些来自 another Whosebug article 的关于 children vs 后代的额外逻辑。
考虑这一点的一个好方法是每个 parent 都包含自己的堆栈上下文。同级元素共享 parent 的堆叠顺序,因此可能会相互重叠。
A child 元素总是根据它的 parent 获取堆叠上下文。因此需要负 z-index 值来推动 child "behind" 其 parent (0) 堆栈上下文。
从 parent 的上下文中删除元素的唯一方法是使用 position: fixed
,因为这实际上会强制它使用 window 作为上下文。
How can I understand this behavior by logic?
对我来说很难从逻辑上理解你的问题。一个parent包含它的children。一个碗可以被另一个碗盖住。但是你不能用碗盖住汤,除非你把汤从碗里拿出来。
z-Index 设置重叠元素的顺序。 parent 不能与其 child 重叠。
恕我直言,这完全合乎逻辑。
您需要了解两件重要的事情:绘画顺序和堆叠上下文。如果您参考 the specification,您可以找到绘制元素的方式和时间。
- Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order (most negative first) then tree order.
- All positioned, opacity or transform descendants, in tree order that fall into the following categories:
- 所有具有 'z-index: auto' 或 'z-index: 0' 的后代,按树顺序排列。
- Stacking contexts formed by positioned descendants with z-indices greater than or equal to 1 in z-index order (smallest first) then tree order.
由此可见,我们首先在第(3)步绘制负数z-index
的元素,然后在第(8)步绘制z-index
等于0的元素,最后绘制负数z-index
等于0的元素在第 (9) 步为正 z-index
,这是合乎逻辑的。我们还可以在the specification的另一部分阅读:
Each box belongs to one stacking context. Each box in a given stacking context has an integer stack level, which is its position on the z-axis relative to other boxes in the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked bottom-to-top according to document tree order.
要了解何时绘制每个元素,您需要知道此堆栈上下文中的其堆栈上下文和其堆栈级别(已定义通过 z-index
)。您还需要知道该元素是否建立了堆叠上下文。这是棘手的部分,因为设置 z-index
将执行此操作:
For a positioned box, the z-index property specifies:
- The stack level of the box in the current stacking context.
- Whether the box establishes a stacking context
Values have the following meanings:
<integer>
This integer is the stack level of the generated box in the current stacking context. The box also establishes a new stacking context.
auto
The stack level of the generated box in the current stacking context is 0. The box does not establish a new stacking context unless it is the root element.
现在我们掌握了所有信息,可以更好地了解每个案例。如果 parent 元素的 z-index
值不是 auto
,那么它将创建一个堆叠上下文,因此 child 元素将被绘制在任何它们的 z-index
是(负或正)。 child 元素的 z-index
将简单地告诉我们 parent 元素内的绘制顺序 (这涵盖了你的第二点).
现在,如果只有 child 元素具有正 z-index
而我们在 parent 元素上不设置任何内容,那么考虑到绘制顺序, child 将稍后绘制(在步骤(9)中)和步骤(8)中的parent。上面画parent的唯一合乎逻辑的方法是增加z-index
,但是这样做会让我们陷入之前的情况,parent会建立一个堆叠上下文,而child元素将属于它。
当设置 positive 时,无法 在 child 元素上方设置 parent z-index
到 child。如果我们将 z-index
设置为 parent 不同于 auto
(正或负)。1
我们可以在其 parent 下方设置 child 的唯一情况是在 child 元素上设置负数 z-index
并保留 parent 在 z-index: auto
,因此这个不会创建堆叠上下文,并且按照绘制顺序首先绘制 child。
除了z-index
,还有other properties that create a stacking context。如果您面临预期的堆叠顺序,您还需要考虑这些属性,以查看是否创建了堆叠上下文。
我们可以从上面得出的一些重要事实:
- Stacking contexts can be contained in other stacking contexts, and together create a hierarchy of stacking contexts.
- Each stacking context is completely independent of its siblings: only descendant elements are considered when stacking is processed.
- Each stacking context is self-contained: after the element's contents are stacked, the whole element is considered in the stacking order of the parent stacking context. ref
1:如果我们考虑使用 3D 转换,则有一些 hacky 方法。
一个元素位于其 parent 元素之下的示例,即使此元素指定了 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;
transform-style: preserve-3d;
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>
我们应该注意,使用这样的 hack 可能会产生一些副作用,因为 transform-style
、perspective
和 transform
会影响 position:absolute/fixed
元素。相关: