css又叫层叠样式表,顾名思义就是一层层叠起来的,虽然在页面中呈现的效果的二维的,但实际是三维的。元素的层叠顺序是基于 z 轴的,并且永远不会有两个在 z 轴上重合的元素。判断元素在 z 轴上的堆叠顺序,不仅仅是直接比较两个元素的 z-index
值的大小,这个堆叠顺序实际由元素的层叠上下文、层叠等级共同决定。
层叠上下文(Stacking Context)
可以想象一个盒子,里面放了东西,这个盒子就代表着一个层叠上下文(盒子里面的东西的层叠关系由上下摆放的顺序决定)。 如果在这个盒子里面还有另外一个盒子,就代表着另一个层叠上下文(另外一个盒子里面东西的层叠关系也是由摆放的顺序决定)。 每一个网页都有一个默认的层叠上下文。 这个层叠上下文(桌子)的根源就是 <html>
。 html 标签中的一切都被置于这个默认的层叠上下文的一个层叠层上(物品放在盒子里)。 当你给一个定位元素赋予了除 auto
外的 z-index 值时,你就创建了一个新的层叠上下文,其中有着独立于页面上其他层叠上下文和层叠层的层叠层。 这也就是为什么有时候我们的子元素设置了 z-index:9999
仍然可能会被其他元素覆盖,这很有可能是他的父元素不争气,排在了覆盖物的后面导致的。如下例所示:
<div class="box1">我是配角</div>
<div class="box2">
<div class="son">我才是主角,我被父元素的层叠上下文束缚了</div>
</div>
<style>
.box1 {
position: absolute;
z-index: 1;
width: 200px;
height: 200px;
background: yellow;
opacity: 0.7;
}
.box2 {
width: 400px;
height: 300px;
position: absolute;
z-index: 0;
background: green;
text-align: right;
}
.box2>.son {
position: relative;
z-index: 9999;
}
</style>
在层叠上下文中,其子元素按照上面解释的规则进行层叠。形成层叠上下文的方法有:
- 根元素
- position 值为 absolute 或 relative,且 z-index值不为 auto
- position 值为 fixed 或 sticky
- z-index 值不为 auto 的 flex 元素,即:父元素 display: flex 或 inline-flex
- opacity 属性值小于 1 的元素
- transform 属性值不为 none的元素
- mix-blend-mode 属性值不为 normal 的元素
- filter、 perspective、 clip-path、 mask、 mask-image、 mask-border、 motion-path 值不为none 的元素
- perspective 值不为 none 的元素
- isolation 属性被设置为 isolate 的元素
- will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值
- -webkit-overflow-scrolling属性被设置touch的元素
总结:
- 层叠上下文可以包含在其他层叠上下文中,并且一起组建了一个有层级的层叠上下文
- 每个层叠上下文完全独立于它的兄弟元素,当处理层叠时只考虑子元素,这里类似于BFC
- 每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会在父级叠上下文中按顺序进行层叠
层叠等级 (Stacking Level)
层叠等级 (层叠水平, Stacking Level) 决定了同一个层叠上下文中元素在 z 轴上的显示顺序的概念;
- 普通元素的层叠等级优先由其所在的层叠上下文决定
- 层叠等级的比较只有在同一个层叠上下文元素中才有意义
- 在同一个层叠上下文中,层叠等级描述定义的是该层叠上下文中的元素在 Z 轴上的上下顺序
注意,层叠等级并不一定由 z-index
决定,只有定位元素的层叠等级才由 z-index
决定,其他类型元素的层叠等级由层叠顺序、他们在 HTML 中出现的顺序、他们的父级以上元素的层叠等级一同决定。
层叠顺序(Stacking Order)
在这个层叠顺序表中,我们可以注意到,在层叠上下文结界中,默认层级最高的是 inline/inline-block元素,层级最低的永远是 background 和 border,默认层级居中的是一些布局用的盒子,这也符合CSS设计的标准,以图文展示为主,其次是布局,最次儿的就是装饰性的 background 和 border 属性了。 除了上面提到的 CSS2.1 的标准,作者在 CSS 层叠领域总结了两条黄金准则,在元素发生层叠的时候,其覆盖关系遵循下面两条准则: (1)谁大谁上:当具有明显的层叠水平标识的时候,如生效的 z-index 属性值,在同一个层叠上下文结界馁,层叠水平值大的那一个覆盖小的那一个。 (2)后来居上:当元素层叠水平一致的时候,在 DOM 流中处于后面的元素会覆盖前面的元素。 结合这两条准则,就可以解释任何元素发生重叠时的显示顺序的问题了。如果下例所示:
<div class="father">
<span class="inline">inline元素</span>
<div class="float"></div>
<div class="block"></div>
</div>
<style>
.father {
position: relative;
background: rgb(255, 255, 0);
}
.block {
background: rgb(255, 0, 0);
width: 100px;
height: 120px;
}
.float {
float: left;
background: rgb(0, 255, 255);
width: 100px;
height: 100px;
margin-left: 50px;
}
.inline {
margin-left: -100px;
background: rgb(0, 255, 0);
}
</style>
运用上图的逻辑,上面的题目就迎刃而解,inline-blcok 的 stacking level 比 float 要高,所以无论 DOM 的先后顺序都堆叠在上面。