前言 {#前言}
在前端开发中你一定用过z-index,它用于让某些元素在视觉上更接近用户,但是有时你又会发现它没有用了,这是因为z-index只是css层叠规则中的一部分,它的起效需要其他css的作用,下面我们就来简单聊聊css层叠这部分的知识,让你不再只是会乱用z-index。
什么是层叠上下文(stacking context) {#什么是层叠上下文(stacking-context)}
这里用一下MDN的定义
翻译过来就是: 层叠上下文是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z轴上延伸,HTML元素依据其自身属性按照优先级顺序占用层叠上下文的空间。
当然这么直接搬文档大部分人一开始肯定是看不懂的,我们可以这么理解,层叠上下文是一个有很多层的盒子,盒子里面有很多书(HTML元素),这些书会根据他们设置的CSS样式摆放在不同的层上,所以我们可以把层叠上下文理解成是一个分层的大容器(虽然这么理解不完全正确)
如何产生层叠上下文 {#如何产生层叠上下文}
这是MDN说明的可以产生层叠上下文的情况
然后我们翻译一下
- 文档的根元素(HTML元素)
- 设置z-index为非auto值的绝对定位和相对定位元素
- 设置了position为fixed或者sticky的元素
- 父元素设置了display:flex,同时自身设置了z-index为非auto值的元素
- opacity小于1的元素
- z-index非auto的网格布局(gird)子元素
- mix-blend-mode属性值不是normal的元素
- 下面这些属性值任意一个不是none的元素
- transform
- filter
- perspective
- clip-path
- mask/mask-image/mask-border
- isolation为isolate值为的元素
- -webkit-overflow-scrolling值为touch的元素
- will-change为非初始值的元素
- contain属性为layout,paint,strict,content的元素
当然你不需要全部记下来,其实记住前六点应该差不多了
再来聊聊层叠等级(stacking level) 和 层叠顺序(stacking order) {#再来聊聊层叠等级(stacking-level)-和-层叠顺序(stacking-order)}
你如果之前看过其他的文章,你就会发现这里我和他们对stacking level的翻译不大一样,其实我一直觉得层叠水平多少有点歧义和不够容易理解,所以我就在这里使用层叠等级这个翻译,其实老实说我并不想放入这两个名词,因为没有必要反而容易混淆,不过最后还是放上来了,因为考虑到有些朋友可能是看过其他博客才来的,怕没有这两个东西不习惯(划掉)
其实层叠等级和层叠顺序在官方文档中没有明确的定义(有可能有,但我没找到),他们只是文档中层叠上下文中用法中偶尔出现了几次的名词,所以我就用自己的理解来下定义了
层叠等级:每一个元素都在包含他的那个层叠上下文中有一个等级,这个等级级就叫做层叠等级,当元素发生重叠时,层叠等级越高,离用户越近,层叠等级小的会被盖住,你还需要注意以下的几点
1. 一个元素只能有一个层叠等级,因为它只能属于一个层叠上下文,就像一本书只能属于一个盒子
2. 一个元素的层叠等级只在它属于的层叠上下文中生效,就像一本书属于一个盒子,他不能跑出这个盒子单独排序
层叠顺序:层叠顺序是一种z轴上的排序规则,这个规则是:同一个层叠上下文中层叠等级高的优先级较高,即层叠等级越高,离用户越近
看看层叠等级有多少级 {#看看层叠等级有多少级}
又到了我们熟悉的丢文档的时间,这是CSS规范2018有关层叠等级的说明
翻译一下:
在一个层叠上下文A中,分层如下(层叠等级逐渐提高):
- 层叠上下文A的背景和边框
- 在这个层叠上下文A中生成了层叠上下文B且z-index为负值的元素
- 常规流非定位块盒
- 非定位的浮动盒子
- 常规流非定位行盒(注意,这里的行盒包括display为inline的元素和inline-bloc的k元素)
- 这一条有三点
- 生成了堆叠上下文且z-index为0的元素
- z-index为auto的定位元素
- 某些不需要设置z-index为数值就能生成堆叠上下文的元素(主要是CSS3新增的)
- z-index为正值的堆叠上下文B
在一个层叠上下文中,层叠等级越高的,离用户越近,如果层叠等级相同,源代码中后面的元素会覆盖前面的元素
概括起来就是谁大谁上,后来居上
看几个例子 {#看几个例子}
例子一 {#例子一}
估计看了这么多的理论知识,不少人是一脸懵逼的,我们在这里就综合一下,用几个例子来运用前面的知识
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
| <body> <div id="box1"> box1:我是z-index为负值的堆叠上下文 </div> <div id="box2"> box2:我是普通块盒 </div> <div id="box3"> box3:我设置了浮动 </div> <div id="box4"> box4:我是行块盒 </div> <div id="box5"> box5:我是定位元素,z-index为0,在蓝色盒子的前面 </div> <div id="box6"> box6:我是定位元素,z-index为auto </div> <div id="box7"> box7:我是定位元素,z-index为0,在蓝色盒子的后面 </div> <div id="box8"> box8:我是z-index为正值的堆叠上下文 </div> </body>
|
CSS
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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 66 67 68 69 70 71 72 73
| div { width: 150px; height: 150px; box-sizing: border-box; padding: 0 30px; } #box1 { background-color: orange; position: relative; z-index: -1; margin-top: 0px; } #box2 { background-color: yellow; margin-top: -60px; } #box3 { background-color: green; float: left; margin-top: -80px; } #box4 { background-color: #00bbff; display: inline-block; margin-top: 0px; margin-left: -150px; } #box6 { background-color: blue; position: relative; margin-top: 0px; top: -80px; z-index: auto; } #box5 { position: absolute; background-color: #4cae4c; z-index: 0; top: 320px; left: 96px; } #box7 { position: absolute; background-color: pink; z-index: 0; top: 320px; left: 328px; } #box8 { background-color: purple; position: relative; z-index: 1; margin-top: 0px; top: -140px; }
|
结果
在这个文档中,一共有5个元素产生了层叠上下文,分别是html元素,box1,box5,box7,box8,
html元素产生的堆叠上下文中有8个元素(box1 - box8),这8个box元素有他们对应的层叠等级(具体的等级参照上面),
层叠等级越高,离用户越近,层叠等级低的元素被盖住,然后层叠等级相同的(比如5,6,7),按照源文件中的先后顺序覆盖
例子二 {#例子二}
现在我们加大难度,把html文件改一下,在box5和box7中分别加一个元素
css不变
|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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
| <div id="box1"> box1:我是z-index为负值的堆叠上下文 </div> <div id="box2"> box2:我是普通块盒 </div> <div id="box3"> box3:我设置了浮动 </div> <div id="box4"> box4:我是行块盒 </div> <div id="box5"> box5:我是定位元素,z-index为0,在蓝色盒子的前面 <div style="position: absolute; z-index: 2; background-color: #8a6d3b; top: 97px; left: 0px"> 我是在box5里面的box5-1,z-index为2,绝对定位 </div> </div> <div id="box6"> box6:我是定位元素,z-index为auto </div> <div id="box7"> box7:我是定位元素,z-index为0,在蓝色盒子的后面 <div style="position: absolute; z-index: -1; background-color: #FF5B17; top: 101px; left: -2px"> 我是在box6里面的box7-1,z-index为-1,绝对定位 </div> </div> <div id="box8"> box8:我是z-index为正值的堆叠上下文 </div>
|
然后看起来匪夷所思的事情发生了
z-index比较大的元素居然在z-index较小的元素下面,这是为什么呢,我们来分析一波,首先最外面的层叠上下文依旧是html元素,
html层叠上下文中有box1 - box8一共8个元素,其中box5和box7因为设置了z-index为0和定位,box5和box7 分别形成了新的层叠上下文,
box5-1和box7-1分别在box5和box7形成的层叠上下文中,box5-1和box7-1设置的z-index只在他们所属的层叠上下文中生效,而他们两个根本不在一个层叠上下文中,所以z-index不能影响他们的覆盖关系,影响他们覆盖关系的是他们所属的层叠上下文,因为box5和box7在html形成的层叠上下文中是box7覆盖box5,所以box7层叠上下文和它层叠上下文中所有的元素都比box5层叠上下文中的元素里用户近,所以box7-1会覆盖box5-1
可以举个形象点的例子,层叠上下文相当于大箱子,没有形成层叠上下文的元素的相当于书,在html这个大箱子中,有box1,box5,box7,box8这几个箱子,box2,box3,box4,box6这几本书,他们离用户的顺序是(从远到近)box1,box2,box3,box4,box5,box6,box7,box8,而box5-1和box7-1是在box5和box7这两个箱子里面的,既然box7这个箱子本身就比box5高,所以box7中的书肯定也比box5中的书高,而box5-1和box7-1设置的z-index只是能让他们在box5和box7这两个箱子中和其他书排序时能排得更高而已
来做个小练习看看是不是掌握了 {#来做个小练习看看是不是掌握了}
现在我们在box6中加个box6-1,设置position为absolute,z-index为1,那么box6-1和box8哪个在前面?
|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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
| <body> <div id="box1"> box1:我是z-index为负值的堆叠上下文 </div> <div id="box2"> box2:我是普通块盒 </div> <div id="box3"> box3:我设置了浮动 </div> <div id="box4"> box4:我是行块盒 </div> <div id="box5"> box5:我是定位元素,z-index为0,在蓝色盒子的前面 <div style="position: absolute;z-index: 2;background-color: #8a6d3b;top: 235px;left: 73px;"> 我是在box5里面的box5-1,z-index为2,绝对定位 </div> </div> <div id="box6"> box6:我是定位元素,z-index为auto <div style="position: absolute;z-index: 1;background-color: #d9534f;top: 90px;left: 127px;"> 我是box6里的box6-1,z-index为1 </div> </div> <div id="box7"> box7:我是定位元素,z-index为0,在蓝色盒子的后面 <div style="position: absolute;z-index: -1;background-color: #FF5B17;top: 236px;left: -44px;"> 我是在box6里面的box7-1,z-index为-1,绝对定位 </div> </div> <div id="box8"> box8:我是z-index为1的堆叠上下文 </div> </body>
|
因为box6没有形成层叠上下文,所以box6-1也在html形成的层叠上下文中,box6-1和box8的z-index都是1,层叠等级相同,根据后来居上原则,box8会覆盖box6-1
后记 {#后记}
那么我要分享的到这里就结束了,如果我有写错的地方或者你有其他想法或者问题,欢迎在评论区留言
测试代码:链接: https://pan.baidu.com/s/1YQvBZ8AiOLQu3c9KLobz0A 提取码: sena