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

转自: https://www.jianshu.com/p/f859efc209f3


默认情况下,网页内容是没有偏移角的垂直视觉呈现,当内容发生层叠的时候,一定会有一个前后的层叠顺序产生。


何为层叠上下文?


盒模型的位置概念,表示每个盒模型元素都可以放在一个三维坐标轴中,其中z轴垂直屏幕,大概就是这样的吧:

层叠上下文,英文称为“stacking context”,是HTML中的一个三维概念,通俗讲就是元素重叠时的上下关系,表现为谁盖着谁,相对用户视角就是谁距离人眼最近(这句话不严谨,因为规则中的z-index为负值与普通元素相比是远离用户双眼的)。


何为层叠水平?


层叠水平决定了同一层叠上下文中元素在z轴上的显示顺序。也通俗讲就是在z轴上谁层叠水平高谁就在最上面(外面)。(其实是绘制先后,层叠水平高的后绘制,会遮盖先绘制的元素)

需要注意的是:
层叠水平只有在同一层叠上下文中比较才有意义。

z-index可以影响定位元素和flex盒子的孩子元素的层叠水平,但它不代表层叠水平,因为所有元素都有层叠水平!


何为层叠顺序?


层叠顺序表示元素发生层叠时有着特定的垂直显示顺序,这种顺序按照一定的规则生成,这就是层叠顺序。
CSS3以前的层叠顺序:

对于这张图的一些解释:
z-index:auto和z-index:0的定位元素虽然看上去效果一样,但是有本质区别。(对于z-index为auto的一般定位元素,其只是普通元素,不会创建层叠上下文,所以层叠时要么看子元素层叠水平,要么按"后来居上"原则;对于z-index为0的一般定位元素,自身会创建层叠上下文,从而会影响子元素的层叠显示问题)

inline/inline-block表现的是内容,所以层叠顺序优先,而块状元素和浮动用作布局,则次之。因为网页中最重要的是展示内容。

背景和边框为创建层叠上下文的元素的,因为他们的内容肯定是覆盖在背景之上的,所以也有层叠关系。

内联元素还有inline-table



层叠准则


谁大谁上:当具有明显层叠水平标示的时候,如z-index值,在同一层叠上下文领域,层叠水平值大的覆盖小的那个;(层叠水平小的先被绘制)
后来居上:当元素水平一致、层叠顺序相同时,在DOM流中处于后面的元素覆盖前面的元素。

如何创建层叠上下文?


MDN中描述:
文档中的层叠上下文由满足以下任一个条件的元素组成:

根元素(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对层叠与层叠上下文

使用float层叠的例子:

当给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与层叠上下文

mix-blend-mode类似于PS中的混合模式

元素和白色背景混合,无论哪种模式,要么全白,要么无变化。(暂时还不理解这句话)
<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与层叠上下文

will-change用于GPU加速
<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
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值