z-index与堆叠上下文
动机
最近项目中同时使用z-index和opacity遇到一些问题,z-index值设了很大,但是不起作用。找了一些资料,重新梳理了z-index的重叠规则。
z-index
MDN中z-index的描述为:用于指定已经定位的元素(即position:relative/absolute/fixed)在文中的堆叠顺序。按照数值放置,高的在上面。
当z-index不为auto时,将产生堆叠上下文(stacking context)。下面结合几个例子说说堆叠上下文是什么。
常规堆叠顺序
没有使用z-index时,默认z-index:auto,此时>不会产生堆叠上下文(stacking context),所有元素都处在同一层,同父元素的层级。
The box does not establish a new local stacking context. The stack level of the generated box in the current stacking context is the same as its parent's box.
此时堆叠顺序如下(从下到上):
根元素(即HTML元素)的background和borders
正常流中非定位后代元素(这些元素顺序按照HTML文档出现顺序,后面的会覆盖前面的)
浮动元素
正常流中已定位后代元素(这些元素顺序按照HTML文档出现顺序,后面的会覆盖前面的)
下面看看例子:
#absdiv1 {
position: absolute;
width: 150px;
height: 200px;
top: 10px;
right: 140px;
border: 1px dashed #990000;
background-color: #ffdddd;
}
#normdiv {
height: 100px;
border: 1px dashed #999966;
background-color: #ffffcc;
margin: 0px 10px 0px 10px;
text-align: left;
}
#flodiv1 {
margin: 0px 10px 0px 20px;
float: left;
width: 150px;
height: 200px;
border: 1px dashed #009900;
background-color: #ccffcc;
}
#flodiv2 {
margin: 0px 20px 0px 10px;
float: right;
width: 150px;
height: 200px;
border: 1px dashed #009900;
background-color: #ccffcc;
}
为了说明效果,div按照相反的堆叠顺序放置
<div id="absdiv1" class="opacity">
<br /><span class="bold">DIV #1</span>
<br />position: absolute;
</div>
<div id="flodiv1" class="opacity">
<br /><span class="bold">DIV #2</span>
<br />float: left;
</div>
<div id="flodiv2" class="opacity">
<br /><span class="bold">DIV #3</span>
<br />float: right;
</div>
<br />
<div id="normdiv">
<br /><span class="bold">DIV #4</span>
<br />no positioning
</div>
在没有z-index的情况下,html顺序为#1->#2->#3->#4->#5,渲染顺序为#4(正常流中非定位后代元素)->#2(浮动元素)->#3(浮动元素)->#1(正常流中已定位后代元素)->#5(正常流中已定位后代元素)。
上述是没有z-index时的默认情况,渲染层就是layer 0。
z-index生成堆叠上下文改变堆叠顺序
z-index有几个关键点:
只适用于已经定位的元素(即position:relative/absolute/fixed)</li>
渲染顺序按照z-index大小,从低到高
z-index生效时将产生堆叠上下文
可以看到,由于#1,#3,#5设置了position,z-index生效,而 #2和#4未生效,z-index:0。
上面div都是同级的,下面看看在子元素中设置z-index的情况。在#3中加入子元素#6 #7,在#4中设置子元素#8。
#3中的子元素#6 #7虽然设置了z-index:10,z-index:11,但仍处于#1的下面。这是因为#3的z-index 生效,生成了堆叠上下文(stacking context),而处在堆叠上下文的元素的z-index只在当前父元素下有效,子堆叠上下文被看做是父堆叠上下文中一个独立的模块,相邻的堆叠上下文完全没关系。
再来看看#4中的子元素#8,由于#4的没有设置position,因此z-index无效,还处在z-index:0中,且没有生成堆叠上下文。而子元素#8 z-index生效,将和#5,#3,#1处在同级,在#3之后,#4之前。
总结:
设置position且z-index不为auto,将产生堆叠上下文,堆叠规则异于常规堆叠。
-
处在堆叠上下文的元素的z-index只在当前父元素下有效,子堆叠上下文被看做是父堆叠上下文中一个独立的模块,相邻的堆叠上下文完全没关系。意味着如果一个元素位于一个最低位置的层,那你z-index设置得再大,它也不会出现在其它层元素的上面。我们可以将产生上下文堆叠的层级按照如下规则理解:
#2,#4z-index未生效(未产生堆叠上下文),同父元素(html)的设置,值为默认auto,即0。
#1,#3,#5 z-index生效(产生堆叠上下文),分别是4,3,1。
#6,#7的父元素#3为3,故#6为3.10(z-index生效,产生堆叠上下文),#7为3.0(z-index未生效,未产生堆叠上下文)
#8父元素#2 为0,#8 z-index生效(产生堆叠上下文),为3.
产生堆叠上下文的几种情况
除了z-index+position,[MDN-stacking_context]中列举了产生堆叠上下文的几种情况。
HTML根文档
当一个元素position为(absolute或relative),且拥有一个z-index值(不为auto)
当一个元素position为fixed或sticky
当一个元素是flexbox的子元素,且拥有一个z-index值(不为auto)
当一个元素被设置了opacity(小于1),transforms, filters, perspective,clip-path,css-regions, paged media,mask / mask-image / mask-border,mix-blend-mode(不为normal), isolation (值为isolate),-webkit-overflow-scrolling (值为touch),will-change 等属性。
以opacity为例,我们在#4上加入opacity:0.5。此时#4生成堆叠上下文,其子元素#8最终为0.3。在#1,#3,#5之下。
参考文献
https://developer.mozilla.org...
https://developer.mozilla.org...
http://www.myexception.cn/HTM...
http://blog.csdn.net/u0143463...
http://www.w3cplus.com/css/wh...
https://www.w3.org/TR/CSS2/zi...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。