分类: CSS

  • 层叠上下文和z-index

    渲染过程和层叠顺序

    浏览器将HTML解析为DOM的同时还创建了另一个树形结构,渲染树(render tree)。渲染树代表了每个元素的视觉样式和位置,同时决定浏览器绘制元素的顺序。

    • 通常情况下(没有使用定位),元素在HTML里出现的顺序决定了绘制顺序。后绘制的元素会出现在先绘制的元素前面。
    • 定位元素时,这种行为会改变。浏览器会先绘制所有非定位的元素,然后绘制定位元素。默认情况下,所有的定位元素会出现在非定位元素前面。

    使用z-index控制层叠顺序

    z-index属性的值可以是任意整数(正负都行)。z表示的是笛卡儿x-y-z坐标系里的深度方向。拥有较高z-index的元素出现在拥有较低z-index的元素前面。拥有负数z-index的元素出现在静态元素后面。

    z-index的行为很好理解,但是使用它时要注意两个小陷阱。

    • z-index只在定位元素上生效,不能用它控制静态元素。
    • 给一个定位元素加上z-index可以创建层叠上下文。

    层叠上下文

    一个层叠上下文包含一个元素或者由浏览器一起绘制的一组元素。其中一个元素会作为层叠上下文的根,比如给一个定位元素加上z-index的时候,它就变成了一个新的层叠上下文的根。所有后代元素就是这个层叠上下文的一部分。

    所有层叠上下文内的元素会按照以下顺序,从后到前叠放:

    • 层叠上下文的根
    • z-index为负的定位元素(及其子元素)
    • 非定位元素
    • z-indexauto的定位元素(及其子元素)
    • z-index为正的定位元素(及其子元素)

    举个例子

    下面这个例子可以用来理解层叠上下文,nested在第一个盒子的层叠上下文中,就算设置了很高的z-index,也会被第二个盒子遮挡。因为第一个盒子形成的层叠上下文在第二个盒子后面。

    <body>
      <div class="box one positioned">
        one
        <div class="absolute">nested</div>
      </div>
      <div class="box two positioned">two
      </div>
    
    </body>
    body {
      margin: 40px;
    }
    
    .box {
      display: inline-block;
      width: 200px;
      line-height: 200px;
      text-align: center;
      border: 2px solid black;
      background-color: #ea5;
      margin-left: -60px;
      vertical-align: top;
    }
    
    .one { margin-left: 0; }
    .two { margin-top: 30px; }
    
    
    .positioned {        (以下5行)每个定位的盒子都创建了一个层叠上下文,z-index为1
      position: relative;               
      background-color: #5ae;           
      z-index: 1;                      
    }                                  
    
    .absolute {
      position: absolute;
      top: 1em;
      right: 1em;
      height: 2em;
      background-color: #fff;
      border: 2px dashed #888;              
      z-index: 100;       ←---- z-index只控制元素在它所处层叠上下文内的层叠顺序
      line-height: initial;
      padding: 1em;
    }

    表现结果

    扩展到实际应用中的场景是,在已经打开的弹窗中再打开一个弹窗,就算第一个弹窗中的某个元素设置了很高的z-index,也还是会被第二个(后绘制)的弹窗挡住。

目录