关于CSS:为什么具有z-index值的元素不能覆盖其子级?

Why can't an element with a z-index value cover its child?

今天,经过数小时的调试,我很难学到了以下规则:

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

如何通过逻辑理解这种行为? 在规格上吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.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;
}
1
2
  1. I can never be covered by parent if my z-index is positive.
  2. Even when my z-index is nagative, I still can never be covered if my parent has any z-index at all.

enter image description here


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

  • 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:

  • All positioned descendants with 'z-index: auto' or 'z-index: 0', in tree order.
  • 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的元素,最后在步骤(9)绘制具有正z-index的元素。 ,这是合乎逻辑的。我们还可以阅读规范的另一部分:

    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.

    An element that establishes a local stacking context generates a box that has two stack levels: one for the stacking context it creates (always 0) and one for the stacking context to which it belongs (given by the z-index property).

    要了解何时绘制每个元素,您需要了解其堆叠上下文以及该堆叠上下文中的堆叠级别(由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:

    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.

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

    现在,如果仅子元素具有正数z-index,而我们在父元素上未设置任何内容,则考虑绘制顺序,子元素将在稍后(步骤(9)中)绘制,父元素在步骤(8)中绘制。在上面绘制父级的唯一逻辑方法是增加z-index,但是这样做会使我们陷入前面的情况,父级将建立一个堆栈上下文,而子元素将属于该上下文。

    为子元素设置正数z-index时,无法使父元素位于子元素上方。如果将z-index设置为不同于auto的父元素(正数或负数),也无法使父项位于子项之上。1

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

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

    我们可以从以上总结得出一些重要事实:

  • 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变换,则有一些骇人听闻的方法。

    元素位于其父元素下的示例,即使该元素指定了z-index

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    .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 */
    }
    1
     

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    .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;
    }
    1
     

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .box {
      width: 100px;
      height: 100px;
      position: absolute;
    }

    body {
      transform-style: preserve-3d;
    }
    1
     

    CSS circular stacking context

    我们应该注意,由于transform-styleperspectivetransform会影响position:absolute/fixed元素,因此使用此类技巧可能会有一些副作用。相关:父母的CSS过滤器破坏了孩子的位置


    考虑这一点的一种好方法是每个父级都包含自己的堆栈上下文。同级元素共享父级的堆叠顺序,因此可能彼此重叠。

    子元素总是基于其父元素获取堆栈上下文。因此,需要一个负的z-index值来将子级推到其父级(0)堆栈上下文的"后面"。

    从元素的父级上下文中删除元素的唯一方法是使用position: fixed,因为这实际上迫使该元素将窗口用于上下文。


    Mozilla文档确实说

    The z-index CSS property sets the z-order of a positioned element and its descendants or flex items.

    这是另一个StackOverflow文章中有关子代与子代的一些其他逻辑。


    How can I understand this behavior by logic?

    对我来说,很难用逻辑来理解你的问题。父母包含其子女。一个碗可以被另一个碗盖住。但是,除非将汤从碗中取出,否则无法用碗盖住汤。

    z-Index设置重叠元素的顺序。父母不能与孩子重叠。

    ImhO完全合乎逻辑。