1. ![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的情况下

    1. <style>
    2. div {
    3. /* box-sizing: border-box; */
    4. border: 10px solid rgba(255, 0, 0, 1);
    5. width: 100px;
    6. height: 100px;
    7. background-color: blue;
    8. }
    9. </style>
    1. <body>
    2. <div>
    3. </div>
    4. </body>
  • 我们在Chrome的调试工具中调试这个透明度(选中数值,按option + 方向键↓可以让数值一点一点下降)

image.png

  • border-box的情况

    1. <style>
    2. div {
    3. box-sizing: border-box;
    4. border: 10px solid rgba(255, 0, 0, 1);
    5. width: 100px;
    6. height: 100px;
    7. background-color: blue;
    8. }
    9. </style>
  • image.png
    由此得出背景的范围是从**border**外部开始的,**background**包括了**border**
    从三维的角度看,border覆盖在background上面

层叠上下文

注:这里只探讨了定位引起的层叠

一个普通div的层叠关系

由上面的例子可以知道,在一个普通的盒子里面他的borderbackground是有摆放顺序的。

但是对于我们用户来说,我们只能看到一个平面。

我们可以通过测试得出一个普通的盒子的层级

  • 根据上面的例子,我们已经知道了,border是在background上面的。

块级子盒子和border谁在上谁在下?

  1. <style>
  2. .outter{
  3. width: 100px;
  4. height: 100px;
  5. border: 10px solid red;
  6. background-color: green;
  7. }
  8. .inner {
  9. width: 20px;
  10. height: 20px;
  11. /* 让块级子盒子移动到border上 */
  12. margin-left: -5px;
  13. background-color: purple;
  14. }
  15. </style>
  1. <body>
  2. <div class="outter">
  3. <!-- 块级子盒子 -->
  4. <div class="inner"></div>
  5. </div>
  6. </body>

结果如图所示,块级子盒子能够压住border,而background肯定也是覆盖在上面了。

image.png

接下来我们再来看看内联子盒子(文字)与块级子盒子的关系

内联子盒子(文字)与块级子盒子的关系

  1. <style>
  2. .outter{
  3. width: 100px;
  4. height: 100px;
  5. border: 10px solid red;
  6. background-color: green;
  7. }
  8. .inner {
  9. width: 20px;
  10. height: 20px;
  11. margin-top: -10px;
  12. background-color: purple;
  13. }
  14. </style>
  1. <body>
  2. <div class="outter">
  3. <!-- 内联子盒子 -->
  4. 我是一句话,我的级别很高
  5. <!-- 块级子盒子 -->
  6. <div class="inner"></div>
  7. </div>
  8. </body>

效果如图所示,内联子元素肯定是比块级子元素的层级高的

image.png

最后我们在对比一下,浮动的块级子元素,普通的块级子元素和内联子元素

浮动的块级子元素,普通的块级子元素和内联子元素

  1. <style>
  2. .outter{
  3. width: 100px;
  4. height: 100px;
  5. border: 10px solid red;
  6. background-color: green;
  7. }
  8. .inner {
  9. width: 20px;
  10. height: 20px;
  11. margin-top: -10px;
  12. background-color: purple;
  13. border: 1px solid chartreuse;
  14. }
  15. .inner_float {
  16. float: left;
  17. width: 30px;
  18. height: 30px;
  19. margin-top: -30px;
  20. margin-left: 20px;
  21. background-color:fuchsia;
  22. }
  23. </style>
  1. <body>
  2. <div class="outter">
  3. <!-- 内联子盒子 -->
  4. 我是一句话,我的级别很高
  5. <!-- 块级子盒子 -->
  6. <div class="inner"></div>
  7. <!-- 浮动的块级子盒子 -->
  8. <div class="inner_float"></div>
  9. </div>
  10. </body>

效果图如下,我给普通的盒子加上了绿色的边框,这样我们可以发现float的子盒子会盖住普通的子盒子,但是无法盖住内联子盒子。

image.png

现在我们就可以对普通的盒子进行一个总结了

对于一个普通的盒子来说,层级是这样的

内联元素(文本)= inline-block > 浮动的块级子元素 > 普通的块级子元素 > border > background

立体的图像如下图所示:

image.png

为什么内联子元素的层级会比块级和浮动高呢?

张鑫旭老师这有个很好的说法。

诸如border/background一般为装饰属性,而浮动和块状元素一般用作布局,而内联元素都是内容。网页中最重要的是什么?当然是内容了哈,对不对! 因此,一定要让内容的层叠顺序相当高,当发生层叠是很好,重要的文字啊图片内容可以优先暴露在屏幕上。

同一层叠上下文的层叠准则

  1. 如果设置了 z-index 那么谁的 z-index 值大,谁就在上面。
  2. 当层叠顺序相同的时候,dom流后面的元素会压住前面的元素。

我们刚刚讨论的是一个普通的元素的层叠水平,我们并没有创建一个层叠上下文。

创建层叠上下文

如何创建层叠上下文呢,其实我们一开始就已经创建了一个层叠上下问,和块级格式上下文一样, html 标签会创建一个层叠上下文。

这就是为什么,绝对定位元素在left/top等值定位的时候,如果没有其他定位元素限制,会相对浏览器窗口定位的原因。

还有一种创建层叠上下文的方法就是:z-index值为数值的定位元素的传统层叠上下文。

position 的值不是 static ,且 z-index 设置了值得时候,就会创建层叠上下文。

当我们不设置 z-index 的时候, z-index 的值默认是 auto

现在这个时候我们再看看完整的层叠上下文关系图
image.png

图片来自于:w3cplus

当然了,根据我们之前在上文的探究的实际上background会在border下面。

重新梳理与相关例子

开天辟地:

html 标签出来的时候,就创建了一个层叠上下文,这就是我们一开始的世界。

一片混沌:

这个时候,我们还没有所谓的定位,大家都是普通的元素,但是也有长幼之分。

也就是 background < border < 普通块级元素 < 普通浮动元素 < 内联元素/文本
image.png

这个就是上面的图,代码可以看上面的。

罪恶的阶级:

在大家一片混沌的年代(也就是只根元素创建的层叠上下文的年代),大家是没有什么太大差别的(都是一家人,只有长幼之分)。

但是——大人,时代变了。

这个时候出现了一个叫定位的东西,和一个叫 z-index 的东西。这两个东西打破了原来的平衡,出现了新的阶级(官府)。

我们作为上帝,可以给某一个元素设置定位,以及 z-index 。我们把他的等级( z-index )设置成1。这个时候,我们就创建一个新的阶级(新的层叠上下文)。

  1. <style>
  2. .containner {
  3. height: 300px;
  4. width: 300px;
  5. padding: 30px;
  6. background-color: yellow;
  7. }
  8. .nomal {
  9. background-color: pink;
  10. width: 60px;
  11. height: 60px;
  12. }
  13. .test {
  14. position: relative;
  15. z-index: 1;
  16. top: -30px;
  17. background-color: red;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <div class="containner">
  23. <div class="nomal">我是一个平民</div>
  24. <div class="test">我是天龙人</div>
  25. </div>
  26. </body>

image.png
我们可以从图中明显的看到,我们的天龙人,作为新的阶级(新的层叠上下文),比原来上下文的内联元素等级都高。

因此也我们的准则可以再加上一条了也就是:

background < border < 普通块级元素 < 普通浮动元素 < 内联元素/文本 < 拥有定位的元素

但是我们并没有好好的讨论 z-index 。这个 z-index 可以理解为地位,当我们的都在同一级的上下文(这里是由 **html** 创建的上下文创建新的层叠上下文的时候, z-index 的值越大,相对应的层级就越高。

  1. <style>
  2. .containner {
  3. height: 300px;
  4. width: 300px;
  5. padding: 30px;
  6. background-color: yellow;
  7. }
  8. .upper1 {
  9. position: relative;
  10. z-index: 1;
  11. background-color: pink;
  12. width: 100px;
  13. height: 60px;
  14. }
  15. .upper100 {
  16. position: relative;
  17. z-index: 100;
  18. top: -25px;
  19. background-color: red;
  20. }
  21. </style>
  22. <body>
  23. <div class="containner">
  24. <div class="upper1">我是天龙人, 等级为1</div>
  25. <div class="upper100">我是天龙人, 等级为100</div>
  26. </div>
  27. </body>

image.png

这个时候我们可以看到,即使大家都是天龙人,也有等级之分( z-index )。 z-index 越大,层级越高。

狐假虎威:

在上面我们看到了,将一个元素设置定位,然后再给他一个 z-index 就会创建出一个新的层叠上下文。但是我们并没有去讨论默认的情况。也就是 z-index = auto

如果我们给一个元素设置定位,但是并没有给它设置 z-index 的话,那么 z-index 的默认值是 auto

为什么要把这一小节的标题叫做狐假虎威呢?因为如果你没有给 z-index 设置数值的话,他是不会创建新的层叠上下文的。但是它在页面中的显示效果却和 z-index = 0 是一样的。

  1. <style>
  2. .containner {
  3. height: 300px;
  4. width: 300px;
  5. padding: 30px;
  6. background-color: yellow;
  7. }
  8. .normal {
  9. position: relative;
  10. z-index: 1;
  11. background-color: pink;
  12. width: 100px;
  13. height: 60px;
  14. }
  15. .upper {
  16. position: relative;
  17. z-index: 100;
  18. top: -30px;
  19. background-color: red;
  20. }
  21. </style>
  22. <body>
  23. <div class="containner">
  24. <div class="normal">我是平民</div>
  25. <div class="upper">我是假的天龙人</div>
  26. </div>
  27. </body>

image.png

用来表示 z-index=autoz-index=0 有区别的例子,请看下面

打狗看主人:

什么叫打狗也要看主人呢,比如我们某一个层级中,分别创建两个层叠上下文, z-index 分别设置为1和2。这个时候我们再在这两个层叠上下文中分别创建一个层叠上下文, z-index 分别是10和1。

画图理解一下就是:
image.png
这个时候,如果我们将 层叠上下文b1层叠上下文a1 叠在一起的时候,显示的结果是 b1 压在了 a1 上。

为什么呢?明明 a1z-index = 10 明显比 b1z-index 要大啊。这就是因为,打狗要看主人,对于层叠上下文 ab 来说, b 的等级是要比 a 的,因此无论 a 里面的层级有多高,都只能在 a 这个上下文里面有效果。

我们依然可以用代码验证一下:

  1. <style>
  2. .containner {
  3. height: 300px;
  4. width: 300px;
  5. padding: 30px;
  6. background-color: yellow;
  7. }
  8. .a {
  9. position: relative;
  10. z-index: 1;
  11. width: 100px;
  12. height: 100px;
  13. }
  14. .a1 {
  15. position: relative;
  16. z-index: 10;
  17. background-color: pink;
  18. }
  19. .b {
  20. position: relative;
  21. width: 100px;
  22. height: 100px;
  23. z-index: 2;
  24. top: -63px;
  25. }
  26. .b1 {
  27. position: relative;
  28. z-index: 1;
  29. background-color: red;
  30. }
  31. </style>
  32. <body>
  33. <div class="containner">
  34. <div class="a">
  35. <div class="a1">我是a1, 我在a里面地位高</div>
  36. </div>
  37. <div class="b">
  38. <div class="b1">我是b1, 我在所有地方地位都高</div>
  39. </div>
  40. </div>
  41. </body>

image.png

这个时候我们再来看一个例子:就是关于 z-index = autoz-index = 0 的区别的。

还是上面那个例子作为原型,我们只需要修改一个地方,结果就会完全不一样。是的,我们将 层叠上下文az-index 改成 auto 。这样就会导致结果完全反过来—— a1 反而压住 b1

但是这里我们为了比较值为 auto0 的区别,我们将a的层级改为auto,将b的层级改为0。
image.png

代码就是修改两个地方的 z-index ,不给出了。直接看结果
image.png
出现这种情况的原因就是 z-index = auto 的时候不会创建层叠上下文。也就是说此时 a 并不是层叠上下文, a1 才是在 html 创建的这个层叠中所创建的层级上下文,而另一个在 html 这个层级中创建的层级上下文是 b ,而 bz-index 是0。毫无疑问 10>0 ,所以 a1 肯定会覆盖 b ,也就肯定会覆盖到 b1 了。

虎落平阳

本来,给一个元素设置定位,并且给定一个数值给 z-index ,这个元素就一飞冲天,凌驾于所有普通元素之上,但是天有不测。如果你给一个元素的 z-index 设置为负值的话,那么他虽然也会创建层级上下文,但是他并不会凌驾于普通元素之上,反而是只比 borderbackground 高。

  1. <style>
  2. /* .containner {
  3. height: 300px;
  4. width: 300px;
  5. padding: 30px;
  6. background-color: yellow;
  7. } */
  8. .normal {
  9. width: 50px;
  10. height: 50px;
  11. background-color: pink;
  12. }
  13. .loser {
  14. position: relative;
  15. z-index: -1;
  16. top: -10px;
  17. width: 100px;
  18. height: 100px;
  19. background-color: red;
  20. }
  21. </style>
  22. <body>
  23. <div class="containner">
  24. <div class="normal">我是平民</div>
  25. <div class="loser">我现在虽然是层级上下文,但我却是个fw</div>
  26. </div>
  27. </body>

image.png
你看,此时连平民(普通的元素)都能遮住层叠上下文了。

再来一个例子

我们可以看到,我刚刚的代码,我是把 containner 注释掉了,我们现在看看不注释掉的效果
image.png
你会发现, 我们所创建出来的层叠上下文居然不见了,其实它只是被黄色遮住了。
image.png
出现这样的原因其实很简单,因为 z-index 为负值的层叠上下文所处的位置是位于创建他的层叠上下文(这个例子中指的是 html )的背景和border上的。而我们的黄色背景并不是加在 html 上的,而是一个普通的 div 上,因此他才不会显示出来。

但是很奇怪的一点是,如果你给 body 加上背景色的话,即使 body 并没有创建层叠上下文, z-index 为负值的层叠上下文,并不会被body的背景所遮盖。这与我们刚刚的分析相悖。我并不清楚为什么,可能所学的知识还不够。
image.png

我又进行了一次探究,当我给 body 设置 border ,然后再把 containner 强行移动到边框上的时候,符合我们分析的结果(border把 z-index 值为负的层叠上下文遮住)出现了。

代码:

  1. <style>
  2. body {
  3. border: 100px solid yellow;
  4. }
  5. .containner {
  6. /* 我这么做是为了将使body的边框能覆盖normal和loser */
  7. margin-left: -50px;
  8. }
  9. .normal {
  10. width: 50px;
  11. height: 50px;
  12. background-color: pink;
  13. }
  14. .loser {
  15. position: relative;
  16. z-index: -1;
  17. top: -10px;
  18. width: 100px;
  19. height: 100px;
  20. background-color: red;
  21. }
  22. </style>
  23. <body>
  24. <div class="containner">
  25. <div class="normal">我是平民</div>
  26. <div class="loser">我现在虽然是层级上下文,但我却是个fw</div>
  27. </div>
  28. </body>

image.png

因此,我猜测,可能浏览器动了手脚。毕竟给 body 设置背景色的时候,浏览器也搞了些小动作。

总结

都在这张图里了。
image.png

图片来自于:w3cplus