CSS中的层叠上下文和层叠顺序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSS中的层叠上下文和层叠顺序相关的知识,希望对你有一定的参考价值。

技术分享

copy @ from http://www.zhangxinxu.com

四、务必牢记的层叠准则

下面这两个是层叠领域的黄金准则。当元素发生层叠的时候,其覆盖关系遵循下面2个准则:

  1. 谁大谁上:当具有明显的层叠水平标示的时候,如识别的z-indx值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。通俗讲就是官大的压死官小的。
  2. 后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在DOM流中处于后面的元素会覆盖前面的元素。

在CSS和html领域,只要元素发生了重叠,都离不开上面这两个黄金准则。因为后面会有多个实例说明,这里就到此为止。

五、层叠上下文的特性

层叠上下文元素有如下特性:

  • 层叠上下文的层叠水平要比普通元素高(原因后面会说明);
  • 层叠上下文可以阻断元素的混合模式(见此文第二部分说明);
  • 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的层叠上下文。
  • 每个层叠上下文和兄弟元素独立,也就是当进行层叠变化或渲染的时候,只需要考虑后代元素。
  • 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中。
  • 觉得多数常见,z-index根本就没有出现的必要。知道了内联元素的层叠水平比块状元素高,于是,某条线你想覆盖上去的时候,需要设置position:relative吗?不需要,inline-block化就可以。因为IE6/IE7 position:relative会创建层叠上下文,很烦的
  • ③. CSS3与新时代的层叠上下文
    CSS3的出现除了带来了新属性,同时还对过去的很多规则发出了挑战。例如,CSS3 transform对overflow隐藏对position:fixed定位的影响等。而这里,层叠上下文这一块的影响要更加广泛与显著。

    如下:

    1. z-index值不为autoflex项(父元素display:flex|inline-flex).
    2. 元素的opacity值不是1.
    3. 元素的transform值不是none.
    4. 元素mix-blend-mode值不是normal.
    5. 元素的filter值不是none.
    6. 元素的isolation值是isolate.
    7. will-change指定的属性值为上面任意一个。
    8. 元素的-webkit-overflow-scrolling设为touch.

    基本上每一项都有很多槽点。

    1. display:flex|inline-flex与层叠上下文
    注意,这里的规则有些负责复杂。要满足两个条件才能形成层叠上下文:条件1是父级需要是display:flex或者display:inline-flex水平,条件2是子元素的z-index不是auto,必须是数值。此时,这个子元素为层叠上下文元素,没错,注意了,是子元素,不是flex父级元素。

    眼见为实,给大家上例子吧。

    如下HTML和CSS代码:

    <div class="box">
        <div>
        	<img src="mm1.jpg">
        </div>
    </div>
    .box {  }
    .box > div { background-color: blue; z-index: 1; }    /* 此时该div是普通元素,z-index无效 */
    .box > div > img { 
      position: relative; z-index: -1; right: -150px;     /* 注意这里是负值z-index */
    }

    结果如下:

    技术分享

    会发现,妹子跑到蓝色背景的下面了。为什么呢?层叠顺序图可以找到答案,如下:
    技术分享

    从上图可以看出负值z-index的层叠顺序在block水平元素的下面,而蓝色背景div元素是个普通元素,因此,妹子直接穿越过去,在蓝色背景后面的显示了。

    现在,我们CSS微调下,增加display:flex, 如下:

    .box { display: flex; }
    .box > div { background-color: blue; z-index: 1; }    /* 此时该div是层叠上下文元素,同时z-index生效 */
    .box > div > img { 
      position: relative; z-index: -1; right: -150px;     /* 注意这里是负值z-index */
    }

    结果:

    技术分享

    会发现,妹子在蓝色背景上面显示了,为什么呢?层叠顺序图可以找到答案,如下:
    技术分享

    从上图可以看出负值z-index的层叠顺序在当前第一个父层叠上下文元素的上面,而此时,那个z-index值为1的蓝色背景<div>的父元素的display值是flex,一下子升官发财变成层叠上下文元素了,于是,图片在蓝色背景上面显示了。这个现象也证实了层叠上下文元素是flex子元素,而不是flex容器元素。

    另外,另外,这个例子也颠覆了我们传统的对z-index的理解。在CSS2.1时代,z-index属性必须和定位元素一起使用才有作用,但是,在CSS3的世界里,非定位元素也能和z-index愉快地搞基。

    2. opacity与层叠上下文
    我们直接看代码,原理和上面例子一样,就不解释了。

    如下HTML和CSS代码:

    <div class="box">
        <img src="mm1.jpg">
    </div>
    .box { background-color: blue;  }
    .box > img { 
      position: relative; z-index: -1; right: -150px;
    }

    结果如下:

    技术分享

    然后价格透明度,例如50%透明:

    .box { background-color: blue; opacity: 0.5;  }
    .box > img { 
      position: relative; z-index: -1; right: -150px;
    }

    结果如下:

    技术分享

    原因就是半透明元素具有层叠上下文,妹子图片的z-index:-1无法穿透,于是,在蓝色背景上面乖乖显示了。

    3. transform与层叠上下文
    应用了transform变换的元素同样具有菜单上下文。

    我们直接看应用后的结果,如下CSS代码:

    .box { background-color: blue; transform: rotate(15deg);  }
    .box > img { 
      position: relative; z-index: -1; right: -150px;
    }

    结果如下:

    技术分享

    妹子同样在蓝色背景之上。

    4. mix-blend-mode与层叠上下文
    mix-blend-mode类似于PS中的混合模式,之前专门有文章介绍-“CSS3混合模式mix-blend-mode简介”。

    元素和白色背景混合。无论哪种模式,要么全白,要么没有任何变化。为了让大家有直观感受,因此,下面例子我特意加了个原创平铺背景:

    .box { background-color: blue; mix-blend-mode: darken;  }
    .box > img { 
      position: relative; z-index: -1; right: -150px;
    }

    结果如下:

    技术分享

    需要注意的是,目前,IE浏览器(包括IE14)还不支持mix-blend-mode,因此,要想看到妹子在背景色之上,请使用Chrome或FireFox。

    同样的,因为蓝色背景元素升级成了层叠上下文,因此,z-index:-1无法穿透,在蓝色背景上显示了。

    5. filter与层叠上下文
    此处说的filter是CSS3中规范的滤镜,不是旧IE时代私有的那些,虽然目的类似。同样的,我之前有提过,例如图片的灰度或者图片的毛玻璃效果等。

    我们使用常见的模糊效果示意下:

    .box { background-color: blue; filter: blur(5px);  }
    .box > img { 
      position: relative; z-index: -1; right: -150px;
    }

    结果如下:

    技术分享

    好吧,果然被你猜对了,妹子蓝色床上躺着,只是你眼镜摘了,看得有些不够真切罢了。

    6. isolation:isolate与层叠上下文
    isolation:isolate这个声明是mix-blend-mode应运而生的。默认情况下,mix-blend-mode会混合z轴所有层叠在下面的元素,要是我们不希望某个层叠的元素参与混合怎么办呢?就是使用isolation:isolate。由于一言难尽,我特意为此写了篇文章:“理解CSS3 isolation: isolate的表现和作用”,解释了其阻隔混合模式的原理,建议大家看下。

    要演示这个效果,我需要重新设计下,如下HTML结构:

    <img src="img/mm2.jpg" class="mode">
    <div class="box">
        <img src="mm1.jpg">
    </div>

    CSS主要代码如下:

    .mode {
      /* 竖妹子绝对定位,同时混合模式 */
      position: absolute; mix-blend-mode: darken;
    }    
    .box {
      background: blue;         
    }
    .box > img { 
      position: relative; z-index: -1;
    }

    结构如下:

    技术分享
    技术分享

    会发现,横妹子被混合模式了。此时,我们给妹子所在容器增加isolation:isolate,如下CSS所示:

    .mode {
      /* 竖妹子绝对定位,同时混合模式 */
      position: absolute; mix-blend-mode: darken;
    }    
    .box {
      background: blue; isolation:isolate;         
    }
    .box > img { 
      position: relative; z-index: -1;
    }

    结果为:

    技术分享
    技术分享

    会发现横着的妹子跑到蓝色背景上面了。这表明确实创建了层叠上下文。

    7. will-change与层叠上下文
    关于will-change,如果有同学还不了解,可以参见我之前写的文章:“使用CSS3 will-change提高页面滚动、动画等渲染性能”。

    都是类似的演示代码:

    .box { background-color: blue; will-change: transform;  }
    .box > img { 
      position: relative; z-index: -1; right: -150px;
    }

    结果如下:

    技术分享

    果然不出所料,妹子上了蓝色的背景。

    七、层叠上下文与层叠顺序

    本文多次提到,一旦普通元素具有了层叠上下文,其层叠顺序就会变高。那它的层叠顺序究竟在哪个位置呢?

    这里需要分两种情况讨论:

    1. 如果层叠上下文元素不依赖z-index数值,则其层叠顺序是z-index:auto可看成z:index:0级别;
    2. 如果层叠上下文元素依赖z-index数值,则其层叠顺序由z-index值决定。

    于是乎,我们上面提供的层叠顺序表,实际上还是缺少其他重要信息。我又花功夫重新绘制了一个更完整的7阶层叠顺序图(同样的版权所有,商业请购买,可得无水印大图):

    技术分享

    大家知道为什么定位元素会层叠在普通元素的上面吗?

    其根本原因就在于,元素一旦成为定位元素,其z-index就会自动生效,此时其z-index就是默认的auto,也就是0级别,根据上面的层叠顺序表,就会覆盖inlineblockfloat元素。

    而不支持z-index的层叠上下文元素天然z-index:auto级别,也就意味着,层叠上下文元素和定位元素是一个层叠顺序的,于是当他们发生层叠的时候,遵循的是“后来居上”准则。

    我们可以速度测试下:

    <img src="mm1" style="position:relative">
    <img src="mm2" style="transform:scale(1);">
    <img src="mm2" style="transform:scale(1);">
    <img src="mm1" style="position:relative">

    技术分享技术分享
    技术分享技术分享

    会发现,两者样式一模一样,仅仅是在DOM流中的位置不一样,导致他们的层叠表现不一样,后面的妹子趴在了前面妹子的身上。这也说明了,层叠上下文元素的层叠顺序就是z-index:auto级别。

    z-index值与层叠顺序
    如果元素支持z-index值,则层叠顺序就要好理解些了,比较数值大小嘛,小盆友都会,本质上是应用的“谁大谁上”的准则。在以前,我们只需要关心定位元素的z-index就好,但是,在CSS3时代,flex子项也支持z-index,使得我们面对的情况比以前要负复杂。然而,好的是,规则都是一样的,对于z-index的使用和表现也是如此,套用上面的7阶层叠顺序表就可以了。

    同样,举个简单例子,看下z-index:-1z-index:1变化对层叠表现的影响,如下两段HTML:

    <div style="display:flex; background:blue;">
       <img src="mm1.jpg" style="z-index:-1;">
    </div>
    <div style="display:flex; background:blue;">
       <img src="mm1.jpg" style="z-index:1;">
    </div>

    最后,会发现,z-index:-1跑到了背景色小面,而z-index:1高高在上。

    技术分享
    技术分享

    一个与层叠上下文相关的有趣的显示现象
    在实际项目中,我们可能会渐进使用CSS3的fadeIn淡入animation效果增强体验,于是,我们可能就会遇到类似下面的现象:

    您可以狠狠地点击这里:CSS3 fadeIn淡入animation动画有趣现象

    有一个绝对定位的黑色半透明层覆盖在图片上,默认显示是这样的:
    技术分享

    但是,一旦图片开始走fadeIn淡出的CSS3动画,文字跑到图片后面去了技术分享
    技术分享

    为什么会这样?

    实际上,学了本文的内容,就很简单了!fadeIn动画本质是opacity透明度的变化:

    @keyframes fadeIn {
      0% { 
        opacity: 0;
      }
      100% {
        opacity: 1;
      }
    }

    要知道,opacity的值不是1的时候,是具有层叠上下文的,层叠顺序是z-index:auto级别,跟没有z-index值的absolute绝对定位元素是平起平坐的。而本demo中的文字元素在图片元素的前面,于是,当CSS3动画只要不是最终一瞬间的opacity: 1,位于DOM流后面的图片就会遵循“后来居上”准则,覆盖文字。

    这就是原因,于是,我们想要解决这个问题就很简单。

    1. 调整DOM流的先后顺序;
    2. 提高文字的层叠顺序,例如,设置z-index:1;

以上是关于CSS中的层叠上下文和层叠顺序的主要内容,如果未能解决你的问题,请参考以下文章

深入理解CSS中的层叠上下文和层叠顺序(转)

CSS层叠上下文、层叠等级、层叠顺序和z-index

CSS堆叠顺序

层叠上下文

CSS中的两个重要概念:层叠上下文和层叠级别

CSS中的两个重要概念:层叠上下文和层叠级别