一、什么是层叠上下文和层叠水平
层叠上下文和层叠水平有一点儿抽象。我们可以吧层叠上下问想象成一张桌子,如果有另一个桌子在他旁边,则代表了另一个层叠上下文。
Stacking context 1由文件根元素构建,Stacking context 2和Stacking context 3是在Stacking context 1的层叠水平之上,并且也创建的自己的层叠上下文,里面有一个新的层叠水平。
我们所创建的每个网页都有一个默认的层叠上下文,层叠上下文的根(上面假设的桌子)就是HTML元素,所有其他元素都会在这个默认的层叠上下文上占据一个层叠水平,或高或低。
二、层叠顺序
-
背景和边框:建立层叠上下文元素的背景和边框。层叠中的最低级
-
负 Z-index:
z-index
为负的后代元素建立的层叠上下文 -
块级盒:文档流内非行内级非定位后代元素
-
浮动盒:非定位浮动元素(即排除了position:absolute/relative/fixed的浮动盒)
-
行内盒:文档流内行内级非定位后代元素
-
Z-index: 0:定位元素。这些元素建立了新层叠上下文(笔者注:不一定,详见后文)
-
正 Z-index:(
z-index
为正的)定位元素。层叠的最高等级
注:
- 原图没有呈现inline-block的层叠顺序,实际上,inline-block和inline水平元素是同等level级别。
- z-index:0实际上和z-index:auto单纯从层叠水平上看,是可以看成是一样的。注意这里的措辞——“单纯从层叠水平上看”,实际上,两者在层叠上下文领域有着根本性的差异。
三、务必牢记的层叠准则
- 谁大谁上:当具有明显的层叠水平标示的时候,如识别的z-indx值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。通俗讲就是官大的压死官小的。
- 后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在DOM流中处于后面的元素会覆盖前面的元素。
四、层叠上下文的创建
1.根层叠上下文
指的是页面根元素,也就是滚动条的默认的始作俑者<html>
元素。这就是为什么,绝对定位元素在left
/top
等值定位的时候,如果没有其他定位元素限制,会相对浏览器窗口定位的原因。
2.定位元素与传统层叠上下文
对于包含有position:relative
/position:absolute
的定位元素,以及FireFox/IE浏览器(不包括Chrome等webkit内核浏览器)(目前,也就是2016年初是这样)下含有position:fixed
声明的定位元素,当其z-index
值不是auto
的时候,会创建层叠上下文。
3.CSS3与新时代的层叠上下文
以下情况会产生新的层叠上下文:
-
根元素(HTML)
-
绝对或相对定位且
z-index
值不为auto
-
一个伸缩项目
Flex Item
,且z-index
值不为auto
,即父元素display: flex|inline-flex
-
元素的
opacity
属性值小于 1 -
元素的
transform
属性值不为none
-
元素的
mix-blend-mode
属性值不为normal
-
元素的
filter
属性值不为normal
-
元素的
isolation
属性值为isolate
-
position: fixed
-
will-change
中指定了上述任意属性,即便你没有直接定义这些属性 -
元素的
-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; }
结果如下:

果然不出所料,妹子上了蓝色的背景。
五、层叠上下文与层叠顺序
一旦普通元素具有了层叠上下文,其层叠顺序就会变高。那它的层叠顺序究竟在哪个位置呢?
这里需要分两种情况讨论:
- 如果层叠上下文元素不依赖
z-index
数值,则其层叠顺序是z-index:auto
可看成z:index:0
级别; - 如果层叠上下文元素依赖
z-index
数值,则其层叠顺序由z-index
值决定。
六、总结
大多数情况下,z-index是不必要使用的。比如,知道了内联元素的层叠水平比块状元素高,于是,某条线你想覆盖上去的时候,只需要inline-block
化就可以。
参考资料:http://webdesign.tutsplus.com/articles/what-you-may-not-know-about-the-z-index-property--webdesign-16892
http://www.zhangxinxu.com/wordpress/2016/01/understand-css-stacking-context-order-z-index/