CSS进阶(15)—— CSS世界的层叠规则(上)

819 阅读7分钟

说到CSS世界的层叠规则,很多人会想到z-index,翻译成中文,叫做"z轴的顺序"。事实上,抛开z-index只有在部分元素中(如定位元素)生效的条件,任何“元素”都无需借助z-index的支持会有自己的层叠规则,这个层叠顺序是基于z轴的。这里我们需要了解一个概念,尽管我们平时看到的电脑屏幕是“二维”的平面,但事实上CSS世界的概念是“三维”的,他和我们人所在的世界一样,经过任意一点可以有三条互相垂直的直线,当然这是三维空间的概念,和本文并无多大关系。

既然都是三维世界的层叠关系,那我们以自己的世界为例,来谈谈05年春晚的一个节目——千手观音。

千手观音这个节目很好的展现了三维世界的层叠关系与所展现的“视觉效果”。以图片平面为xy平面,视觉上呈现了排在第一个的人的完整图像,已第一个人为准,排在他后面的人,构成了三维世界的z轴,由于后面的人在xy平面上的“大部分”图像都被遮挡,只能看到由于角度不同而呈现出来的手臂,因此最终在"xy"平面上呈现出千手观音的效果。(三维世界的坐标轴如下所示,我不敢在上图中乱涂乱画,我怕文字狱)

通过上面这个例子,我们需要明白一条CSS三维世界的第一准则:永远不会有两个在z轴上重合的“元素”!

1.什么是层叠上下文

在理解CSS世界的层叠规则之前,我们必须要了解两个关键词——层叠上下文和层叠水平。本章的前面两个小节就单独来讲一讲这两个关键词。首先,什么是层叠上下文?这是HTML中的一个官方的三维概念,这个说法听起来有点像之前提到过的“块状格式化上下文”(BFC),这里我们复习一下块状格式化上下文做了一件什么事情,就是声明了xxx属性的元素他一不小心拥有了xxx特性。放在这里也是同理,在CSS世界中,只要当前元素拥有了某些属性(如position:relative;定位加上z-index不为auto),就会使得当前元素被“层叠上下文”。那么这个被“层叠上下文”会使当前元素拥有什么特性呢?

在讲BFC的时候,我们提到了一个结界的概念,放在这里,也依然适用,拥有层叠上下文特性的元素会生成一个“层叠结界”,这个“层叠结界”内部的所有元素会永远的被束缚在某一段z轴空间内部,且永远不能打破这个外层的“层叠结界”。这也就是为什么有时候我们的子元素设置了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>

2.什么是层叠水平

在本开头,我提出了一个概念——CSS世界中任何两个“元素”不会在z轴上重合,由于不是所有元素需要被“CSS层叠上下文”,但所有的元素都需要有个z轴上的显示顺序,因此对于这些没有被“层叠上下文”的元素如何显示的问题就需要层叠水平的帮忙了。事实上,我们需要明确一个概念,就是所有的元素都拥有层叠水平,这是一个默认的“计算值”,但由于在声明了层叠上下文后,这个计算值可以忽略不计,因此通常我们只在同一个层叠上下文中考虑层叠水平的问题。

说了这么多,你可能仍然不能明白层叠水平是个什么东西,这里我们就用个例子来说明一下。

<div id="father">
    <span id="son1">我是大儿子</span>
    <span id="son2">我是二儿子</span>
</div>

在上例中,我们的父容器里面有两个span标签,这两个span标签并不会产生所谓的“重叠”,但他们其实并没有处在同一个z坐标中,而且可以肯定的是,二儿子的显示顺序要优于大儿子,这是由普通元素的默认层叠水平决定的,至于为什么是二儿子在大儿子上面,后面会详细说到。

3.理解元素层叠顺序的两大法则

在理解了层叠上下文和层叠水平的概念后,我们可以来好好聊一聊CSS世界的显示规则了,也就是本节要说的层叠顺序。由于所有元素都自带层叠规则,因此CSS制定了一套详细的标准来规范元素在z轴上的显示顺序。如下图所示:

可以看到,在每一个层叠上下文的结界中,任何内部元素的层级都要高于backgroud/border,因此background/border组成了层叠上下文的“地板”,而层叠上下文的“天花板”取决于内部元素的z-index:正值的大小(理论上是这样)。

在这个层叠顺序表中,我们可以注意到,在层叠上下文结界中,默认层级最高的是inline/inline-block元素,层级最低的永远是background和border,默认层级居中的是一些布局用的盒子,这也符合CSS设计的标准,以图文展示为主,其次是布局,最次儿的就是装饰性的background和border属性了。

除了上面提到的CSS2.1的标准,作者在CSS层叠领域总结了两条黄金准则,在元素发生层叠的时候,其覆盖关系遵循下面两条准则:

(1)谁大谁上:当具有明显的层叠水平标识的时候,如生效的z-index属性值,在同一个层叠上下文结界馁,层叠水平值大的那一个覆盖小的那一个。

(2)后来居上:当元素层叠水平一致的时候,在DOM流中处于后面的元素会覆盖前面的元素。

结合这两条准则,就可以解释任何元素发生重叠时的显示顺序的问题了。

4.结合实例理解层叠规则

在本章中我们了解了很多CSS世界中层叠规则的概念,下面我们需要结合上面三个小节的概念做一个综合性的测试,主要是为了验证CSS2.1的标准在谷歌浏览器下的表现是否依旧稳定。

第一个测试验证:inline>float>block>background

在进行测试的时候,需要用到margin负边距使得元素重叠,测试代码如下:

<!-- 综合测试1 -->
<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>float>block>background的结论成立。

第二个测试验证:z-index正值>z-index:0约等于z-index:auto>z-index负值

<!-- 综合测试2 -->
<div class="father">
     <div class="zIndex-1">负的z-index</div>
    <div class="zIndexAuto">z-index:auto</div>
    <div class="zIndex0">z-index:0</div>
    <div class="zIndex1">正z-index</div>
</div>
<style>
.father{
    position: relative;
    background: rgb(255,255,0);
}
.zIndex-1{
    position: absolute;
    width: 100px;
    height: 200px;
    background: rgb(255,0,0);
    left: 0;
    top: 0px;
    z-index: -1;
}
.zIndex0{
    position: absolute;
    width: 100px;
    height: 100px;
    background: rgb(0,255,0);
    left: 0;
    top: 100px;
    z-index: 0;
}
.zIndexAuto{
    position: absolute;
    width: 100px;
    height: 150px;
    background: rgb(255,0,255);
    left: 0;
    top: 50px;
    z-index: auto;
}
.zIndex1{
    position: absolute;
    width: 100px;
    height: 50px;
    background: rgb(0,255,255);
    left: 0;
    top: 150px;
    z-index: 1;
}
</style>

在层叠水平上,z-index:auto和z-index:0的层叠顺序是相同的,因此遵循后来居上的原则,但是z-index:0和z-index:auto在创建层叠上下文结界上有本质区别,这点在下一章节会详细论述,感兴趣的同学可以测试下上述所有元素混杂在一起的时候的层叠顺序。本章主要就是些概念性的东西,为下一章深入了解做个准备。

不忘初心,方得始终

喜欢博主的童鞋可以扫描二维码加博主好友~ 也可以扫中间二维码入驻博主的粉丝群(708637831)~当然你也可以扫描二维码打赏并直接包养帅气的博主一枚。