对于z-index和层叠模型的理解

401 查看

几个概念

  • 层叠上下文

    • 层叠上下文模型可看做CSS的三维盒子模型,有创建层叠上下文能力的元素可作为层叠容器存在,按照层叠顺序表存放其他层叠元素。
    • 一个元素,在层叠上的容器,是它的第一个具有层叠上下文能力的祖先(一直向上找到第一个能容纳它的祖先)
    • 具有创建层叠上下文能力的元素有:
      • 根元素 (HTML标签),
      • z-index 值不为 "auto"的 绝对/相对定位,
      • 一个 z-index 值不为 "auto"的 flex 项目 (flex item),即:父元素 display: flexinline-flex,
      • opacity 属性值小于 1 的元素(参考 the specification for opacity),
      • transform 属性值不为 "none"的元素,
      • mix-blend-mode 属性值不为 "normal"的元素,(混合模式)
      • filter值不为“none”的元素,
      • perspective值不为“none”的元素,
      • isolation 属性被设置为 "isolate"的元素,
      • position: fixed的元素
      • 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值(参考 这篇文章
      • -webkit-overflow-scrolling 属性被设置 "touch"的元素
  • 层叠顺序:在一个层叠上下文容器里,层叠上下文元素它自己和它的直接子层叠元素是安装下表渲染的:(越先提到越早渲染)
    1. 层叠上下文元素的背景
    2. 负z-index的元素(越小越早)
    3. block元素
    4. 具有float的元素
    5. inline/inline-block盒子
    6. z-index:auto / z-index:0 (等级一样,但z-index:auto原则上不创建层叠上下文)、非因z-index创建的层叠上下文元素
    7. 正z-index的元素(越大越晚)
    8. 如果遇到相同等级的,在dom流里先遇到的先渲染,即后来居上
    9. 层叠上下文元素它自己属于2-7的其中一个 一般属于2、6、7

实际的渲染的顺序

我们把一个 有创建层叠上下文能力的元素称之A 接下来讲一下怎么从A开始渲染 (最开始的A就是根元素HTML标签)

  1. 准备一个逻辑上的空数组。
  2. 把A放进数组。
  3. 取出A的所有后代。
  4. 对于数组里的每一个不具有创建层叠上下文能力的元素,取出它的所有后代。
  5. 重复4到数组不再变化。到这一步,A的所有直接子后代还有它自己,都在数组里了。这些元素都依托A为舞台来渲染。
  6. 然后把数组里的元素,按照层叠顺序渲染。
  7. 去掉数组里所有不具有创建层叠上下文能力的元素。
  8. 对于数组里所有具备创建层叠上下文能力的元素,它们的子孙将依托它们为舞台来渲染,因此对他们中的每一个重复1-8。

于是乎,最终渲染的效果特点:

  1. 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的层叠上下文。
  2. 每个层叠上下文和兄弟层叠上下文独立,也就是当进行层叠渲染的时候,每个层叠上下文元素只需要考虑自己盒子里的。
  3. 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中。(类比大版本号、爹说了算)

demo

demo1:爹的地位说了算

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
        * {
            margin: 0;
        }
        html {
            padding: 20px;
            font: 12px/20px Arial, sans-serif;
        }
        div {
            opacity: 0.7;
            position: relative;
        }
        h1 {
            font: inherit;
            font-weight: bold;
        }
        #div1,
        #div2 {
            border: 1px dashed #696;
            padding: 10px;
            background-color: #cfc;
        }
        #div1 {
            z-index: 5;
            margin-bottom: 190px;
        }
        #div2 {
            z-index: 2;
        }
        #div3 {
            z-index: 4;
            opacity: 1;
            position: absolute;
            top: 40px;
            left: 180px;
            width: 330px;
            border: 1px dashed #900;
            background-color: #fdd;
            padding: 40px 20px 20px;
        }
        #div4,
        #div5 {
            border: 1px dashed #996;
            background-color: #ffc;
        }
        #div4 {
            z-index: 6;
            margin-bottom: 15px;
            padding: 25px 10px 5px;
        }
        #div5 {
            z-index: 1;
            margin-top: 15px;
            padding: 5px 10px;
        }
        #div6 {
            z-index: 3;
            position: absolute;
            top: 20px;
            left: 180px;
            width: 150px;
            height: 125px;
            border: 1px dashed #009;
            padding-top: 125px;
            background-color: #ddf;
            text-align: center;
        }
    </style>
</head>
<body>
    <div id="div1">
        <h1>Division Element #1</h1>
        <code>
            position: relative;<br/>
            z-index: 5;
        </code>
    </div>

    <div id="div2">
        <h1>Division Element #2</h1>
        <code>
            position: relative;<br/>
            z-index: 2;
        </code>
    </div>

    <div id="div3">

        <div id="div4">
            <h1>Division Element #4</h1>
            <code>
                position: relative;<br/>
                z-index: 6;
            </code>
        </div>

        <h1>Division Element #3</h1>
        <code>
            position: absolute;<br/>
            z-index: 4;
         </code>

        <div id="div5">
            <h1>Division Element #5</h1>
            <code>
                position: relative;<br/>
                    z-index: 1;
            </code>
        </div>

    ​​​​    <div id="div6">
            <h1>Division Element #6</h1>
            <code>
                position: absolute;<br/>
                    z-index: 3;
                </code>
        </div>
    </div>
</body>
</html>

demo2:父级层叠上下文(层叠意义上的容器)是自下往上具有创建上下文能力的第一个祖先

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
        body {
            position: absolute;
        }
        .div1 , .div3 {
            width: 100px;
            height: 100px;
            margin-left: 100px;
            margin-top: 50px;
            background-color: yellow;
        }
        .div2 , .div4 {
            position: relative;
            width: 50px;
            height: 50px;
            margin-left: -40px;
            background-color: red;
            z-index: -1;
        }
        .div3 {
            position: relative;
            z-index: 0;
        }
    </style>
</head>
<body>
    <div class="div1">
        div1
        <div class="div2">
            div2
        </div>
    </div>
    <!-- div1没有创建层叠上下文的能力,所以div1和div2在层叠层级上,都是body的直接子元素,所以div2会在下面,渲染在body的背景上方,在block元素div1下方 -->
    <div class="div3">
        div3
        <div class="div4">
            div4
        </div>
    </div>
    <!-- div3有创建层叠上下文的能力,所以div2在层叠层级上,是div3的子元素,因此会渲染在div3的背景上方 -->
</body>
</html>