爱凉拌菜真是太好了

再谈层叠上下文(stacking context)

最开始由于对z-index和层叠上下文不理解,导致在项目中使用某些属性时出现了问题。现在来总结一下z-index和层叠上下文的一些东西

层叠上下文

层叠上下文是一个三维概念。想象一下HTML元素是在屏幕上一层一层铺起来的,最上面的一层会被优先看到,下面的层会被上面的挡住

生成层叠上下文的条件:

  • 根元素
  • position: relative 或者absolute,并且z-index不为auto
  • position: fixed 或者sticky
  • display 为flex的子元素,并且z-index不为auto
  • opacity < 1
  • mix-blend-mode 不为normal
  • transform、filter、perspective、clip-path或mask不为none
  • isolation: isolate
  • -webkit-overflow-scrolling: touch

层叠上下文是可包含的,独立的。每个层叠上下文与其相邻的层叠上下文互不干扰,每个层叠上下文可以包含层叠上下文。

层叠顺序

层叠上下文的概念还是有点空洞,大部分时候只要记住层叠上下文的排列顺序就行了

  1. 根元素的背景和边框
  2. 普通流(normal flow)的后代元素按照他们在HTML中出现的先后顺序进行层叠
  3. 浮动块元素
  4. 常规流的后代行内元素
  5. 后代已定位元素按照他们在HTML中出现顺序进行层叠

比如说下面一个例子:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
width: 500px;
margin: 0 auto;
color: #fff;
}
#box1 {
float: left;
width: 200px;
height: 200px;
background-color: rgba(255, 0, 0, .8);
}
#box2 {
width: 300px;
height: 200px;
background-color: rgba(0, 255, 0, .8);
}
#box3 {
width: 200px;
height: 200px;
background-color: rgba(0, 0, 255, .8);
margin-top: -100px;
}
#box4 {
top: -50px;
position: relative;
width: 200px;
height: 200px;
background-color: rgba(0, 255, 255, .8);
}
#box5 {
top: 350px;
position: absolute;
width: 200px;
height: 200px;
background-color: rgba(255, 0, 255, .8);
}
.inlineBox1 {
margin-top: 20px;
color: #fff;
display: inline-block;
/*width: 300px;*/
background-color: rgba(0, 0, 0, 1);
}
</style>
</head>
<body>
<div id="box1">float #box1</div>
<div id="box2" class="normal">
normal flow1 #box2
</div>
<div class="inlineBox1">inline-block</div>
<div id="box3" class="normal">normal flow2 #box3</div>
<div id="box4">position relative #box4</div>
<div id="box5">position absolute #box5</div>
<div class="inlineBox2">inline-block</div>
</body>
</html>

可以看到float 元素#box1的确覆盖了普通流的#box2#box3(第3个原则)

普通流的#box3 覆盖了普通流的#box2(第2个原则)

position: relative的#box4 覆盖了normal flow 的#box3(第5个原则)

position: absolute的#box5覆盖了#box4(第5个原则)

inlineBox1#box3 之上 (第4个原则)

z-index

上面的顺序没有说明z-index 对层叠顺序的影响。如果已定位元素为z-index:auto,那么上面的顺序是完全ok的。如果设置了z-index,那么表现又会不一样。

具体为:

  1. 根元素的背景和边框
  2. z-index: -
  3. 普通流(normal flow)的后代元素按照他们在HTML中出现的先后顺序进行层叠
  4. 浮动块元素
  5. 常规流的后代行内元素
  6. z-index: auto
  7. z-index: +

现在我们给#box4 和 #box5添加z-index

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#box4 {
top: -50px;
position: relative;
width: 200px;
height: 200px;
background-color: rgba(0, 255, 255, .8);
z-index: 1
}
#box5 {
top: 350px;
position: absolute;
width: 200px;
height: 200px;
background-color: rgba(255, 0, 255, .8);
z-index: -1;
}

再来看看效果:

没错,#box5 成功的跑到了#box4的下面;注意#box5的底部还漏出了‘inline-block’字样,这个是原本就放在#box5下面的inlineBox2。第一个例子没有显现出来,现在显示出来了。

现在看另外一个例子:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
width: 500px;
margin: 0 auto;
color: #fff;
}
#box4 {
position: relative;
width: 200px;
height: 200px;
background-color: rgba(0, 255, 255, .8);
z-index: 1
}
#box5 {
margin-top: -100px;
position: absolute;
width: 200px;
height: 200px;
background-color: rgba(255, 0, 255, .8);
z-index: -1;
}
#box5-1 {
margin-top: 10px;
position: absolute;
width: 100px;
height: 100px;
background-color: rgba(255, 0 , 0, .8);
z-index: 9999;
}
#box5-2 {
position: absolute;
width: 100px;
height: 100px;
background-color: rgba(0, 0, 255, 0.8);
z-index: -1;
margin-left: 80px;;
margin-top: 20px;
}
</style>
</head>
<body>
<div id="box4">position relative #box4 z-index: 1</div>
<div id="box5">
position absolute #box5 z-index: -1
<div id="box5-1">#box5-1 z-index: 9999</div>
<div id="box5-2">#box5-2 z-index: -1</div>
</div>
</body>
</html>

结果是这样的:

可以看到z-index: 9999 的#box-5-1并没有出现在所有元素的最上方,而是被#box4遮住了。 之所以会出现这种情况,是由于z-index只对当前层叠上下文有影响。 #box5设置了z-index: -1 过后就生成了层叠上下文,所以该层叠上下文包含的子元素的层叠顺序是基于该层叠上下文进行的。

层叠层次应该是这样:

  • root element
    • box4
    • box5
      • box5-1
      • box5-2

其他属性对层叠顺序的影响

一旦普通元素具有了层叠上下文,其层叠顺序就会变高。 一旦某个元素具备产生层叠上下文的条件(比如:opacity: 0.8),那么层叠的顺序会发生变换。

具体又分为两种条件:

  • 不依赖z-index: 层叠顺序相当于z-index: auto
  • 依赖z-index: 层叠顺序由z-index决定

来看一看opacity < 1时候的表现:

1
2
<div id="box1">#box1 normal flow</div>
<div id="box2">#box2 normal flow</div>
1
2
3
4
5
6
7
8
9
10
11
12
#box1 {
width: 200px;
height: 200px;
background-color: rgba(0, 255, 255, .8);
opacity: 0.8;
}
#box2 {
margin-top: -100px;
width: 200px;
height: 200px;
background-color: rgba(255, 0, 255, .8);
}

没错!box1 在box2上面。如果不加opacity:0.8,normal flow按照规则应该是会遮挡box1,然而现在box1却在box2上面。

现在给#box2加上position:relative

1
2
3
4
5
6
7
#box2 {
margin-top: -100px;
width: 200px;
height: 200px;
background-color: rgba(255, 0, 255, .8);
position: relative;
}

???box2又跑到上面去了?
因为position: relative 并没有指定z-index,所以默认的层叠顺序的优先级就是z-index: auto。

不依赖z-index: 层叠顺序相当于z-index: auto

而opacity 不依赖z-index, 所以层叠顺序的优先级也和z-index: auto一样。同时,由于box2在HTML文档中位于box1的下方,因此box2遮挡了box1

由此看出记住层叠顺序相当重要哦!

我感觉脑子有点乱~~~