大家有没有遇到这样的问题,给一个元素加上transform或者opacity等效果后,它的子元素的z-index就“失效了”?
这里普及一个概念:stacking context,中文翻译叫做“堆叠上下文”,这里我们简称做“层”。
实际上,真正决定页面上堆叠顺序的并不是z-index,而是层。一个层就是页面上Z轴的一个单位,并且页面的Z轴并不是一维的,而是多维的,每一个层内部还可以包含多个层。
每层用各自的z-index值来比较排序(正值>0>auto(已定位)>auto(未定位)>负值)。 (已定位指position不为static,position为static的元素无法给z-index赋值)
我们来看下面这张图:
图中DIV1有A和B两个子元素,DIV2有C和D两个子元素。
最终呈现在页面上的效果如图,堆叠顺序从上到下依次是A,B,C,D。A会显示在最上面。
这就像是栋房子,2楼的小矮子会位于1楼的大高个上面。
什么?你不相信这个结果?那我们就来实验一下。
我们先看例一:
<style>
div{position:abosolute; width:100px; height:100px;}
</style>
<div id="A">
<div id="B" style="background:green"></div>
</div>
<div id="C" style="background:pink; left:20px; top:50px"></div>
A和C的z-index都等于auto(默认值),它们就像是都在楼房的1楼,那应该怎么确定堆叠顺序呢?它们会按照文档的排列顺序来决定堆叠顺序,C在A的文档下面,所以会覆盖A,也会覆盖B。
如果我们给绿色box加上z-index:2 , 结果如例二:
<style>
div{position:abosolute; width:100px; height:100px;}
</style>
<div id="A">
<div id="B" style="background:green; z-index:2"></div>
</div>
<div id="C" style="background:pink; left:20px; top:50px"></div>
B的z-index=2后会在A内部产生新的堆叠上下文,就不能再按照文档顺序来排列了。B会覆盖C。(注意,A内其他z-index=auto的元素依然会被C覆盖)
如果我们给A加上z-index=-1,会如何呢?来看例三:
<style>
div{position:abosolute; width:100px; height:100px;}
</style>
<div id="A" style="z-index:-1">
<div id="B" style="background:green; z-index:2"></div>
</div>
<div id="C" style="background:pink; left:20px; top:50px"></div>
由于z-index=-1,此时的A就像是在负1楼,即使B的z-index=2也会被C覆盖。
说到这里,大家应该明白了怎么判断堆叠顺序了。
有人会问,这些和一开始说的transform和opacity没关系啊?
实际上,transform和opacity等特性,会和z-index一样产生新的堆叠上下文。
MDN上说明了哪些情况会产生新的堆叠上下文:
the root element (HTML),
positioned (absolutely or relatively) with a z-index value other than “auto”,
a flex item with a z-index value other than “auto”,
elements with an opacity value less than 1,
elements with a transform value other than “none”,
elements with a mix-blend-mode value other than “normal”,
elements with isolation set to “isolate”, on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is “auto”,
specifing any attribute above in will-change even you don’t write themselves directly