转自: https://www.jianshu.com/p/f859efc209f3
默认情况下,网页内容是没有偏移角的垂直视觉呈现,当内容发生层叠的时候,一定会有一个前后的层叠顺序产生。
何为层叠上下文?
层叠上下文,英文称为“stacking context”,是HTML中的一个三维概念,通俗讲就是元素重叠时的上下关系,表现为谁盖着谁,相对用户视角就是谁距离人眼最近(这句话不严谨,因为规则中的z-index为负值与普通元素相比是远离用户双眼的)。
何为层叠水平?
需要注意的是:
层叠水平只有在同一层叠上下文中比较才有意义。
z-index可以影响定位元素和flex盒子的孩子元素的层叠水平,但它不代表层叠水平,因为所有元素都有层叠水平!
何为层叠顺序?
CSS3以前的层叠顺序:
对于这张图的一些解释:
z-index:auto和z-index:0的定位元素虽然看上去效果一样,但是有本质区别。(对于z-index为auto的一般定位元素,其只是普通元素,不会创建层叠上下文,所以层叠时要么看子元素层叠水平,要么按"后来居上"原则;对于z-index为0的一般定位元素,自身会创建层叠上下文,从而会影响子元素的层叠显示问题)
inline/inline-block表现的是内容,所以层叠顺序优先,而块状元素和浮动用作布局,则次之。因为网页中最重要的是展示内容。
背景和边框为创建层叠上下文的元素的,因为他们的内容肯定是覆盖在背景之上的,所以也有层叠关系。
内联元素还有inline-table
层叠准则
后来居上:当元素水平一致、层叠顺序相同时,在DOM流中处于后面的元素覆盖前面的元素。
如何创建层叠上下文?
文档中的层叠上下文由满足以下任一个条件的元素组成:
根元素(HTML)
绝对定位(absolute)或相对定位(relative),并且z-index值不为"auto"
一个flex项目(flex item),且z-index不为"auto"
元素的opacity属性值小于1
元素的transform属性值不为"none"
元素的mix-blend-mode属性值不为"normal"
元素的isolation设置为"isolate"
filter的值不为"none"
will-change指定的属性值为上面任意一个
元素的-webkit-overflow-scrolling设为touch
新版谷歌浏览器设置position:fixed必定创建层叠元素上下文,无论z-index是不是数字
总结一下就是:
页面根元素html天生具有层叠上下文,为“根层叠上下文”
z-index值不为auto而是数值的定位元素(position:relative | absolute)
其他CSS3属性
空口无凭,以例为证
不设置z-index的层叠
<div style="position: absolute;">div #1</div>
<div style="position: relative;">div #2</div>
<div style="position: relative;">div #3</div>
<div style="position: absolute;">div #4</div>
<div>div #5</div>
由于属于同一层叠水平,所以层叠顺序按照“后来居上”原则;
float层叠
<div style="position: absolute;">div #1 absolute</div>
<div style="float:left;">div #2 float-left</div>
<div style="float:right;">div #3 float-right</div>
<div style="position: absolute;">div #4 absolute</div>
<div>div #5 no-position</div>
设置了z-index的层叠
<div style="position:absolute; z-index:5;"> div#1 z-index:5 </div>
<div style="position:relative; z-index:3;"> div#2 z-index:3 </div>
<div style="position:relative; z-index:2;"> div#3 z-index:2 </div>
<div style="position:absolute; z-index:1;"> div#4 z-index:1 </div>
<div style="position:static; z-index:8;"> div#5 z-index:8 </div>
虽然div#5的z-index值最大,但是由于它不是定位元素(position: relative | absolute),所以它依然在层叠的最下面,因为他是普通元素,不具备层叠上下文。
层叠上下文的实例
1. 同一层叠上下文
<div style="position:relative; ">
<div style="position:absolute; z-index:1;"></div>
</div>
<div style="position:relative;">
<div style="position:absolute;"></div>
</div>
可看出只有div2创建了层叠上下文,(根元素本身就带层叠上下文)虽然div2、div3、div4不在同一个BFC中,但是都处于html的根层叠上下文中,且div2 的z-index最高,所以它处于最上方。
注意:当单独给div4设置更高的z-index时,div4会被提到最上层;但是当设置div3位最高z-index时,div3作为父元素会带着div4这个子元素一起跑到最上面。
2. 不同层叠上下文
<div style="position:relative;">div1
<div style="position:absolute; z-index:2;">div2</div>
</div>
<div style="position:relative; z-index:1;">div3
<div style="position:absolute; z-index:100">div4</div>
</div>
即使div4的z-index:100是最大的,但是div4和div2不在同一层叠上下文中,而div2和div3在同一层叠上下文中(html根元素层叠),并且div2的层叠水平更高,所以div2会在div3之上,而div4只是div3的子元素,本身它的层叠上下文的等级就比div2低一级。
将代码做修改,给div1也创建层叠上下文:
<div style="position:relative; z-index:1;">div1
<div style="position:absolute; z-index:2;">div2</div>
</div>
<div style="position:relative; z-index:1;">div3
<div style="position:absolute; z-index:100">div4</div>
</div>
现在div1,div3都各自创建了层叠上下文,所以div2和div4不再有直接层叠关系,而要看他们的父元素。(div2被遮盖是因为根据“后来居上”原理,div3层叠水平高于div1)
小结:
同一层叠上下文中,看各自的层叠水平;
不同层叠上下文中,看他们的父元素层叠水平
CSS3对应的新的层叠上下文
1. opacity对层叠与层叠上下文
当给div#2设置opacity:0.99以及给div#5设置opacity:0.8后层级都得到了提升(注意,div#2提升到了div#1的上面,但是依然在div#4的下面)
解释:
根据CSS3中的解释:
opacity<1的非定位元素,会被当做z-index:0且opacity:1的定位元素,进行层叠计算
opacity<1的定位元素,会按照层叠顺序中的z-index规则进行计算,只不过,即使z-index是auto,仍然会被创建层叠上下文。
2. display:flex | inline-flex与层叠上下文
父级元素必须是display:flex或者display:inline-flex水平;
子元素的index不是auto,必须是数字;
然后这个子元素即item(注意不是父元素)就形成了层叠上下文。
先看看未设置flex box的情况
<div class="box">
<div style="background: #fc0; z-index: 1">
<!-- 这个div只是一个普通元素,所以z-index不起作用 -->
![](img/b0 (3).jpg)
</div>
</div>
添加flex box
<div style="display: flex;">
<div style="background: #fc0; z-index: 1;">
<!-- 这个div只是一个普通元素,所以z-index不起作用 -->
![](img/b0 (3).jpg)
</div>
</div>
这样即使中间那层div不是定位元素,但是由于其父元素为flex box,所以作为子元素的它(前提z-index为数值)也能产生层叠上下文。这样中间层的div的background将处于层叠顺序的最底层,而img的z-index为负值层叠水平比它的高。
3. transform与层叠上下文
<div class="box">
<div style="background: #fc0; transform: rotate(-25deg);">
很显然transform使div形成了层叠上下文
![](img/b0 (3).jpg)
</div>
</div>
4. mix-blend-mode与层叠上下文
元素和白色背景混合,无论哪种模式,要么全白,要么无变化。(暂时还不理解这句话)
<div class="box">
<div style="background: #fc0; mix-blend-mode: darken;">
![](img/b0 (3).jpg)
</div>
</div>
需要注意的是,IE系列包括edge都不支持改属性。
5. filter滤镜效果与层叠上下文
<div class="box">
<div style="background-color: #fc0; -webkit-filter: blur(5px);">
<!-- chrome浏览器需要加上浏览器前缀 -->
![](img/b0 (3).jpg)
</div>
</div>
6. will-change与层叠上下文
<div class="box">
<div style="background-color: #fc0; will-change: transform;">
![](img/b0 (3).jpg)
</div>
</div>
至于isolation:isolate属性比较复杂,另外会单独学习。
总结
元素设置了z-index后,必须将position设置为fiexd/absolute/relative中的一个才会创建层叠上下文;计算层叠顺序时,要先考虑元素所处的层叠上下文,层叠上下文之间的层叠关系直接决定父元素集合之间的层叠关系;
根元素(<html>)拥有一个根层叠上下文。
参考
作者:即将离
链接:https://www.jianshu.com/p/f859efc209f3
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。