![image.png](https://cdn.nlark.com/yuque/0/2021/png/2451693/1609868224939-48cdc820-0aab-4204-881c-4a3a51cd4ef2.png#height=404&id=bWloi&margin=%5Bobject%20Object%5D&name=image.png&originHeight=480&originWidth=649&originalType=binary&ratio=1&size=39181&status=done&style=none&width=546)<br /> —— 封面 层叠上下文关系图
层叠上下文在css中是一个重要的基础概念,之所以出现层叠是因为在页面中元素的排列是一个三维的空间,而我们只能看到一个平面,因此产生了层叠。
下面这篇文章将会从一个普通盒子的层叠逐步讲到层叠上下文,以及丰富的例子来直观地看到层叠的效果。
问题引入——盒子的border与background
background
的范围是从哪里到哪里的?
content-box
的情况下<style>
div {
/* box-sizing: border-box; */
border: 10px solid rgba(255, 0, 0, 1);
width: 100px;
height: 100px;
background-color: blue;
}
</style>
<body>
<div>
</div>
</body>
我们在Chrome的调试工具中调试这个透明度(选中数值,按
option + 方向键↓
可以让数值一点一点下降)
border-box
的情况<style>
div {
box-sizing: border-box;
border: 10px solid rgba(255, 0, 0, 1);
width: 100px;
height: 100px;
background-color: blue;
}
</style>
由此得出背景的范围是从**border**
外部开始的,**background**
包括了**border**
从三维的角度看,border
覆盖在background
上面
层叠上下文
注:这里只探讨了定位引起的层叠
一个普通div的层叠关系
由上面的例子可以知道,在一个普通的盒子里面他的border
和background
是有摆放顺序的。
但是对于我们用户来说,我们只能看到一个平面。
我们可以通过测试得出一个普通的盒子的层级
- 根据上面的例子,我们已经知道了,
border
是在background
上面的。
块级子盒子和border
谁在上谁在下?
<style>
.outter{
width: 100px;
height: 100px;
border: 10px solid red;
background-color: green;
}
.inner {
width: 20px;
height: 20px;
/* 让块级子盒子移动到border上 */
margin-left: -5px;
background-color: purple;
}
</style>
<body>
<div class="outter">
<!-- 块级子盒子 -->
<div class="inner"></div>
</div>
</body>
结果如图所示,块级子盒子能够压住border
,而background
肯定也是覆盖在上面了。
接下来我们再来看看内联子盒子(文字)与块级子盒子的关系
内联子盒子(文字)与块级子盒子的关系
<style>
.outter{
width: 100px;
height: 100px;
border: 10px solid red;
background-color: green;
}
.inner {
width: 20px;
height: 20px;
margin-top: -10px;
background-color: purple;
}
</style>
<body>
<div class="outter">
<!-- 内联子盒子 -->
我是一句话,我的级别很高
<!-- 块级子盒子 -->
<div class="inner"></div>
</div>
</body>
效果如图所示,内联子元素肯定是比块级子元素的层级高的
最后我们在对比一下,浮动的块级子元素,普通的块级子元素和内联子元素
浮动的块级子元素,普通的块级子元素和内联子元素
<style>
.outter{
width: 100px;
height: 100px;
border: 10px solid red;
background-color: green;
}
.inner {
width: 20px;
height: 20px;
margin-top: -10px;
background-color: purple;
border: 1px solid chartreuse;
}
.inner_float {
float: left;
width: 30px;
height: 30px;
margin-top: -30px;
margin-left: 20px;
background-color:fuchsia;
}
</style>
<body>
<div class="outter">
<!-- 内联子盒子 -->
我是一句话,我的级别很高
<!-- 块级子盒子 -->
<div class="inner"></div>
<!-- 浮动的块级子盒子 -->
<div class="inner_float"></div>
</div>
</body>
效果图如下,我给普通的盒子加上了绿色的边框,这样我们可以发现float
的子盒子会盖住普通的子盒子,但是无法盖住内联子盒子。
现在我们就可以对普通的盒子进行一个总结了
对于一个普通的盒子来说,层级是这样的
内联元素(文本)= inline-block > 浮动的块级子元素 > 普通的块级子元素 > border > background
立体的图像如下图所示:
为什么内联子元素的层级会比块级和浮动高呢?
张鑫旭老师这有个很好的说法。
诸如
border
/background
一般为装饰属性,而浮动和块状元素一般用作布局,而内联元素都是内容。网页中最重要的是什么?当然是内容了哈,对不对! 因此,一定要让内容的层叠顺序相当高,当发生层叠是很好,重要的文字啊图片内容可以优先暴露在屏幕上。
同一层叠上下文的层叠准则
- 如果设置了
z-index
那么谁的z-index
值大,谁就在上面。 - 当层叠顺序相同的时候,dom流后面的元素会压住前面的元素。
我们刚刚讨论的是一个普通的元素的层叠水平,我们并没有创建一个层叠上下文。
创建层叠上下文
如何创建层叠上下文呢,其实我们一开始就已经创建了一个层叠上下问,和块级格式上下文一样, html
标签会创建一个层叠上下文。
这就是为什么,绝对定位元素在left
/top
等值定位的时候,如果没有其他定位元素限制,会相对浏览器窗口定位的原因。
还有一种创建层叠上下文的方法就是:z-index值为数值的定位元素的传统层叠上下文。
当 position
的值不是 static ,且 z-index
设置了值得时候,就会创建层叠上下文。
当我们不设置
z-index
的时候,z-index
的值默认是auto
。
现在这个时候我们再看看完整的层叠上下文关系图
图片来自于:w3cplus
当然了,根据我们之前在上文的探究的实际上background会在border下面。
重新梳理与相关例子
开天辟地:
当 html
标签出来的时候,就创建了一个层叠上下文,这就是我们一开始的世界。
一片混沌:
这个时候,我们还没有所谓的定位,大家都是普通的元素,但是也有长幼之分。
也就是 background
< border
< 普通块级元素
< 普通浮动元素
< 内联元素/文本
。
这个就是上面的图,代码可以看上面的。
罪恶的阶级:
在大家一片混沌的年代(也就是只根元素创建的层叠上下文的年代),大家是没有什么太大差别的(都是一家人,只有长幼之分)。
但是——大人,时代变了。
这个时候出现了一个叫定位的东西,和一个叫 z-index
的东西。这两个东西打破了原来的平衡,出现了新的阶级(官府)。
我们作为上帝,可以给某一个元素设置定位,以及 z-index
。我们把他的等级( z-index
)设置成1。这个时候,我们就创建一个新的阶级(新的层叠上下文)。
<style>
.containner {
height: 300px;
width: 300px;
padding: 30px;
background-color: yellow;
}
.nomal {
background-color: pink;
width: 60px;
height: 60px;
}
.test {
position: relative;
z-index: 1;
top: -30px;
background-color: red;
}
</style>
</head>
<body>
<div class="containner">
<div class="nomal">我是一个平民</div>
<div class="test">我是天龙人</div>
</div>
</body>
我们可以从图中明显的看到,我们的天龙人,作为新的阶级(新的层叠上下文),比原来上下文的内联元素等级都高。
因此也我们的准则可以再加上一条了也就是:
background
< border
< 普通块级元素
< 普通浮动元素
< 内联元素/文本
< 拥有定位的元素
但是我们并没有好好的讨论 z-index
。这个 z-index
可以理解为地位,当我们的都在同一级的上下文(这里是由 **html**
创建的上下文)创建新的层叠上下文的时候, z-index
的值越大,相对应的层级就越高。
<style>
.containner {
height: 300px;
width: 300px;
padding: 30px;
background-color: yellow;
}
.upper1 {
position: relative;
z-index: 1;
background-color: pink;
width: 100px;
height: 60px;
}
.upper100 {
position: relative;
z-index: 100;
top: -25px;
background-color: red;
}
</style>
<body>
<div class="containner">
<div class="upper1">我是天龙人, 等级为1</div>
<div class="upper100">我是天龙人, 等级为100</div>
</div>
</body>
这个时候我们可以看到,即使大家都是天龙人,也有等级之分( z-index
)。 z-index
越大,层级越高。
狐假虎威:
在上面我们看到了,将一个元素设置定位,然后再给他一个 z-index
就会创建出一个新的层叠上下文。但是我们并没有去讨论默认的情况。也就是 z-index = auto
如果我们给一个元素设置定位,但是并没有给它设置 z-index
的话,那么 z-index
的默认值是 auto
。
为什么要把这一小节的标题叫做狐假虎威呢?因为如果你没有给 z-index
设置数值的话,他是不会创建新的层叠上下文的。但是它在页面中的显示效果却和 z-index = 0
是一样的。
<style>
.containner {
height: 300px;
width: 300px;
padding: 30px;
background-color: yellow;
}
.normal {
position: relative;
z-index: 1;
background-color: pink;
width: 100px;
height: 60px;
}
.upper {
position: relative;
z-index: 100;
top: -30px;
background-color: red;
}
</style>
<body>
<div class="containner">
<div class="normal">我是平民</div>
<div class="upper">我是假的天龙人</div>
</div>
</body>
用来表示
z-index=auto
和z-index=0
有区别的例子,请看下面
打狗看主人:
什么叫打狗也要看主人呢,比如我们某一个层级中,分别创建两个层叠上下文, z-index
分别设置为1和2。这个时候我们再在这两个层叠上下文中分别创建一个层叠上下文, z-index
分别是10和1。
画图理解一下就是:
这个时候,如果我们将 层叠上下文b1
和 层叠上下文a1
叠在一起的时候,显示的结果是 b1
压在了 a1
上。
为什么呢?明明 a1
的 z-index = 10
明显比 b1
的 z-index
要大啊。这就是因为,打狗要看主人,对于层叠上下文 a
与 b
来说, b
的等级是要比 a
的,因此无论 a
里面的层级有多高,都只能在 a
这个上下文里面有效果。
我们依然可以用代码验证一下:
<style>
.containner {
height: 300px;
width: 300px;
padding: 30px;
background-color: yellow;
}
.a {
position: relative;
z-index: 1;
width: 100px;
height: 100px;
}
.a1 {
position: relative;
z-index: 10;
background-color: pink;
}
.b {
position: relative;
width: 100px;
height: 100px;
z-index: 2;
top: -63px;
}
.b1 {
position: relative;
z-index: 1;
background-color: red;
}
</style>
<body>
<div class="containner">
<div class="a">
<div class="a1">我是a1, 我在a里面地位高</div>
</div>
<div class="b">
<div class="b1">我是b1, 我在所有地方地位都高</div>
</div>
</div>
</body>
这个时候我们再来看一个例子:就是关于 z-index = auto
和 z-index = 0
的区别的。
还是上面那个例子作为原型,我们只需要修改一个地方,结果就会完全不一样。是的,我们将 层叠上下文a
的 z-index
改成 auto
。这样就会导致结果完全反过来—— a1
反而压住 b1
。
但是这里我们为了比较值为 auto
和 0
的区别,我们将a的层级改为auto,将b的层级改为0。
代码就是修改两个地方的 z-index
,不给出了。直接看结果
出现这种情况的原因就是 z-index = auto
的时候不会创建层叠上下文。也就是说此时 a
并不是层叠上下文, a1
才是在 html
创建的这个层叠中所创建的层级上下文,而另一个在 html
这个层级中创建的层级上下文是 b
,而 b
的 z-index
是0。毫无疑问 10>0
,所以 a1
肯定会覆盖 b
,也就肯定会覆盖到 b1
了。
虎落平阳
本来,给一个元素设置定位,并且给定一个数值给 z-index
,这个元素就一飞冲天,凌驾于所有普通元素之上,但是天有不测。如果你给一个元素的 z-index
设置为负值的话,那么他虽然也会创建层级上下文,但是他并不会凌驾于普通元素之上,反而是只比 border
和 background
高。
<style>
/* .containner {
height: 300px;
width: 300px;
padding: 30px;
background-color: yellow;
} */
.normal {
width: 50px;
height: 50px;
background-color: pink;
}
.loser {
position: relative;
z-index: -1;
top: -10px;
width: 100px;
height: 100px;
background-color: red;
}
</style>
<body>
<div class="containner">
<div class="normal">我是平民</div>
<div class="loser">我现在虽然是层级上下文,但我却是个fw</div>
</div>
</body>
你看,此时连平民(普通的元素)都能遮住层叠上下文了。
再来一个例子
我们可以看到,我刚刚的代码,我是把 containner
注释掉了,我们现在看看不注释掉的效果
你会发现, 我们所创建出来的层叠上下文居然不见了,其实它只是被黄色遮住了。
出现这样的原因其实很简单,因为 z-index
为负值的层叠上下文所处的位置是位于创建他的层叠上下文(这个例子中指的是 html
)的背景和border上的。而我们的黄色背景并不是加在 html
上的,而是一个普通的 div
上,因此他才不会显示出来。
但是很奇怪的一点是,如果你给 body
加上背景色的话,即使 body
并没有创建层叠上下文, z-index
为负值的层叠上下文,并不会被body的背景所遮盖。这与我们刚刚的分析相悖。我并不清楚为什么,可能所学的知识还不够。
我又进行了一次探究,当我给 body
设置 border
,然后再把 containner
强行移动到边框上的时候,符合我们分析的结果(border把 z-index
值为负的层叠上下文遮住)出现了。
代码:
<style>
body {
border: 100px solid yellow;
}
.containner {
/* 我这么做是为了将使body的边框能覆盖normal和loser */
margin-left: -50px;
}
.normal {
width: 50px;
height: 50px;
background-color: pink;
}
.loser {
position: relative;
z-index: -1;
top: -10px;
width: 100px;
height: 100px;
background-color: red;
}
</style>
<body>
<div class="containner">
<div class="normal">我是平民</div>
<div class="loser">我现在虽然是层级上下文,但我却是个fw</div>
</div>
</body>
因此,我猜测,可能浏览器动了手脚。毕竟给 body
设置背景色的时候,浏览器也搞了些小动作。
总结
都在这张图里了。
图片来自于:w3cplus