发布于 

层叠上下文、层叠水平、层叠顺序与z-index

实现按钮效果:在鼠标移入按钮时,按钮的原背景颜色被左侧移入的新背景颜色覆盖,并且不影响按钮中的文字显示。

如图:

图1

在这里我很自然就想到了伪元素before和过渡transition,但在设置z-index又出现了问题,要么移入的新背景没有覆盖原背景,要么按钮的文字被新背景覆盖。我就疑惑,z-index的值不是可以设置层叠关系,大的显示在最前面,小的显示在后面吗?

通过查看别人的博客和《CSS世界》,发现我对层叠关系的理解过于片面,要想正确设置层叠,就必须要理解四点:层叠上下文、层叠水平、层叠顺序与z-index

层叠上下文

层叠上下文,是HTML中的一个三维的概念。如果一个元素含有层叠上下文,我们可以理解为这个元素在z轴上就“高人一等”。按照我的理解,z轴就是我们正对着屏幕或网页时,穿透所有元素的一条垂直线,众HTML元素按照一定的优先级在z轴上排列。

层叠上下文有如下特性

  • 层叠上下文的层叠水平要比普通元素高。

  • 层叠上下文可以阻断元素的混合模式。

  • 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的“层叠上下文”。

  • 每个层叠上下文和兄弟元素独立,也就是说,当进行层叠变化或渲染的时候,只需要考虑后代元素。

  • 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中。

层叠上下文的创建

  • 文档根元素(<html>);
  • position值为 absolute(绝对定位)或 relative(相对定位)且z-index值不为 auto 的元素;
  • position值为 fixed(固定定位)或 sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);
  • flex容器的子元素,且 z-index 值不为 auto
  • grid容器的子元素,且 z-index 值不为 auto
  • opacity属性值小于 1 的元素;
  • 更多请查看 [MDN文档](层叠上下文 - CSS:层叠样式表 | MDN (mozilla.org))

层叠准则

(1)谁大谁上:当具有明显的层叠水平标识的时候,如生效的 z-index 属性值,在同一

个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。

(2)后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在 DOM 流中处于后面的

元素会覆盖前面的元素。

层叠水平

层叠水平决定了同一个层叠上下文中元素在 z 轴上的显示顺序。所有的元素都有层叠水平,包括层叠上下文元素,也包括普通元素。然而,对普通元素的层叠水平探讨只局限在当前层叠上下文元素中.

层叠顺序

层叠顺序,表示元素发生层叠时有着特定的垂直显示顺序。

层叠顺序图:

图3

一旦普通元素具有层叠上下文,其层叠顺序就会变高。那它的层叠顺序究竟在哪个位置、哪个级别呢?

这里需要分两种情况讨论:

(1)如果层叠上下文元素不依赖 z-index 数值,则其层叠顺序是 z-index:auto,可看成 z:index:0 级别;

(2)如果层叠上下文元素依赖 z-index 数值,则其层叠顺序由 z-index 值决定。

我们都知道定位元素会层叠在普通元素上面,其背后原因就是:元素一旦成为定位元素,其 z-index 就会自动生效,此时其 z-index 就是默认的 auto,也就是0级别,根据上面的层叠顺序表,就会覆盖inline或block或float元素。

例子1:定位元素与层叠上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
      <!--图1-->
<div style="position:relative; z-index:auto;">
<!-- 美女 -->
<img src="na.jpg" style="position:absolute; z-index: 2;">
</div>
<div style="position:relative; z-index:auto;">
<!-- 风景 -->
<img src="img1.jpg" style="position:relative; z-index: 1;">
</div>

<!--图2-->
<div style="position:relative; z-index:0;">
<!-- 美女 -->
<img src="na.jpg" style="position:absolute; z-index:2;">
</div>
<div style="position:relative; z-index:0;">
<!-- 风景 -->
<img src="img1.jpg" style="position:relative; z-index:1;">
</div>

结果如下图所示:

图2

为什么图1的风景图会被美女图覆盖?为什么图2却是美女图被风景图覆盖?

先对图1进行分析:包含图片的两个兄弟div(z-index:auto)是一个普通的定位元素,于是,里面的两个img元素的层叠比较就不受父级的影响,并且两个img元素有着明显不一的z-index,因此遵循“谁大谁上”的准则,所以,z-index为2的哪个“美女”就显示在z-index为1的“风景”上面。

在图2中,z-index的值变成数值,哪怕是0,都会创建一个层叠上下文。此时,层叠规则就发生了变化。两个img元素的层叠顺序比较变成了优先比较其父层叠上下文元素的层叠顺序。这里,由于外面的两个div都是z-index:0,两者层叠顺序一样大,此时遵顼“后来居上”准则,所以,位于后面的“风景”就自然而然显示在“美女”上面,而img元素上的z-index不起作用。

例子2:z-index负值的使用

模拟纸张效果,该效果的亮点是纸张的边角有卷起来的效果

图4

1
2
3
<div class="container">
<div class="page"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.container{
display: flex;
justify-content: center;
align-items: center;
width: 600px;
height: 600px;
background: #666;
/*创建层叠上下文*/
position: relative;
z-index: 0;
}
.page{
width: 400px;
height: 400px;
background: #f5da41;
position: relative;
}
.page:after{
width: 30%;
height: 20%;
content: "";
box-shadow: 0 8px 16px rgba(0, 0, 0, .3);
position: absolute;
bottom: 0;
right: 0;
/*层叠上下文(灰色背景之上),定位元素(黄色纸张)之下*/
z-index: -1;

}

.container 灰色背景通过 position:relative;z-index:0 创建了层叠上下文,.page仅有 position:relative 而没有设置 z-index 值,因此只能算 z-index:auto 程度的定位元素,于是,z-index:-1 边角阴影就完美地藏在了层叠上下文(灰色背景)之上、普通定位元素(黄色纸张)之下。在清楚z-index负值和层叠关系后,文章开头那个按钮效果也可通过z-index负值实现的。