🧃序言
最近在整理一些很偏的面经题,想起来很久以前被问到的一道题,就是 position
和 z-index
。短短 10min
问了这两个属性,大概直接把周一问懵了。那个时候的心情可能是这样的……
于是,一鼓作气,不懂的知识咱还是得补呀,万一下回又直接被问懵了,那就是死不知悔改了不是。
最后,通过各种资料的查询和理解,整理了下文。内容主要涵盖 position
各个取值的解析以及关于 z-index
的使用。
下面开始进入本文的讲解~🧐
🍷一、文章结构抢先知
在文章开始讲解之前,我们先用一张思维导图来了解本文所要讲解的知识。详情见下图👇
了解完思维导图之后,现在开始进入本文的讲解。
🍸二、position
1. position的取值
通常情况下, position
有以下几个取值。具体如下:
取值 | 含义 | 说明 |
---|---|---|
static | 静态定位 | 对象遵循标准文档流,top,right,bottom,left 等属性失效。 |
relative | 相对定位 | 对象遵循标准文档流中,依赖top,right,bottom,left 等属性相对于该对象在标准文档流中的位置进行偏移,同时可通过 z-index 定义层叠关系。 |
absolute | 绝对定位 | 对象脱离标准文档流,使用 top,right,bottom,left 等属性进行绝对定位(相对于 static 定位以外的第一个父元素进行绝对定位) ,以及可通过 z-index 定义层叠关系。 |
fixed | 固定定位 | 对象脱离标准文档流,使用 top,right,bottom,left 等属性进行绝对定位(相对于浏览器窗口进行绝对定位)同时可通过 z-index 定义层叠关系。 |
sticky | 粘性定位 | 可以说是相对定位 relative 和固定定位 fixed 的结合。元素固定的相对偏移是相对于离它最近的具有滚动框的祖先元素,如果祖先元素都不可以滚动,那么是相对于 viewport 来计算元素的偏移量。 |
2. 标准文档流
我们先来看下标准文档流的定义:
所谓标准文档流,指的是在不使用其他与排列和定位相关的特殊 CSS
规则时,元素的默认排列规则。
理解完定义之后,我们来看看各个取值的使用效果。
3. 各取值解析
(1)static
static
,是默认的 position
值。它没有特殊的定位,且遵循标准文档流。我们用例子来展示一下。
先附上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>static</title>
</head>
<style>
div{
width: 100px;
height: 100px;
margin: 40px auto;
}
.one{
background-color: #99d98c;
}
.two{
background-color: #76c893;
}
</style>
<body>
<div class="one"></div>
<div class="two"></div>
</body>
</html>
现在来看演示效果:
大家可以看到,正如我们所想的,规规矩矩的出现在我们面前,跟我们平常实现其他内容所遵循的规则也基本一样。所以这里不做过多解释。
(2)relative
relative
,对象遵循标准文档流,依赖 top
,right
,bottom
,left
等属性相对于该对象在标准文档流中的位置进行偏移,同时可通过 z-index
定义层叠关系。我们现在用一个例子来展示一下。
先附上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>relative</title>
</head>
<style>
body{
margin: 0 300px;
}
div{
width: 200px;
height: 200px;
padding: 20px;
}
.one{
background-color: #99d98c;
position: relative;
left: 40px;
top: 60px;
}
.two{
background-color: #76c893;
}
</style>
<body>
<div class="one">1</div>
<div class="two">2</div>
</body>
</html>
现在来看演示效果:
大家可以看到, relative
是相对于该对象所处的标准文档流中的位置,依据 left
和 top
进行定位(当然也可以使用 right
和 bottom
,本例仅用以上两个属性做说明)。同时, left
和 top
并不会改变该对象原本在文档流中的占位空间。
值得注意的是,如果设置为 margin
和 padding
属性时,该对象在标准文档流中的占位空间也将会随之改变。
附上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>relative</title>
</head>
<style>
body{
margin: 0 300px;
}
div{
width: 200px;
height: 200px;
padding: 20px;
}
.one{
background-color: #99d98c;
position: relative;
left: 40px;
top: 60px;
margin: 0 0 60px 40px;
}
.two{
background-color: #76c893;
}
</style>
<body>
<div class="one">1</div>
<div class="two">2</div>
</body>
</html>
现在我们来看下浏览器的演示效果:
大家可以看到,当设置了 margin
属性时,该对象仍然跟随着其所处的标准文档流中的占位空间的变化而变化。
(3)absolute
absolute
,对象脱离标准文档流,使用 top
, right
, bottom
, left
等属性进行绝对定位(相对于 static
定位以外的第一个父元素进行绝对定位) ,以及可通过 z-index
定义层叠关系。
先来看个例子,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
body{
margin: 50px 300px;
}
.father-ele{
width: 300px;
height: 300px;
background-color: #168aad;
position: relative;
}
.son-ele{
width: 200px;
height: 200px;
position: static;
background-color: #76c893;
margin-left: 20px;
}
.three{
width: 100px;
height: 100px;
background-color: #99d98c;
}
.four{
width: 100px;
height: 100px;
position: absolute;
left: 0;
top: 0;
background-color: #b5e48c;
}
</style>
<body>
<div class="father-ele">
1
<div class="son-ele">
2
<div class="three">3</div>
<div class="four">4</div>
</div>
</div>
</body>
</html>
具体效果如下:
从上面的定义中我们了解到,绝对定位 absolute
是脱离标准文档流的,且是相对于 static
定位以外第一个父元素,并且使用 left和top
或 right和bottom
进行绝对定位。所以大家可以看到上图,设置了 absolute
的 four
相对于 father-ele
进行定位。
值得一提的是,在使用 absolute
绝对定位时,必须指定 left
、 top
、 right
和 bottom
中的至少一个,否则 left/right/top/bottom
属性将会使用默认值 auto
。这将导致对象遵从标准文档流,在前一个对象之后立即被呈递,简单讲就是都变成 relative
,并且会占用文档空间。
还有就是,如果同时设置了 left/right
属性,那么 left
生效。同理如果 top/bottom
同时存在时, top
生效。
(4)fixed
fixed
,对象脱离标准文档流,使用 top
, right
, bottom
, left
等属性进行绝对定位(相对于浏览器窗口进行绝对定位)同时可通过 z-index
定义层叠关系。
先来看个例子,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>fixed</title>
</head>
<style>
body{
margin: 50px 300px;
}
.father-ele{
width: 300px;
height: 300px;
background-color: #168aad;
position: relative;
}
.son-ele{
width: 200px;
height: 200px;
position: static;
background-color: #76c893;
margin-left: 200px;
}
.three{
width: 100px;
height: 100px;
position: fixed;
left: 20px;
top: 20px;
background-color: #99d98c;
}
.four{
width: 100px;
height: 100px;
background-color: #b5e48c;
}
</style>
<body>
<div class="father-ele">
1
<div class="son-ele">
2
<div class="three">3</div>
<div class="four">4</div>
</div>
</div>
</body>
</html>
具体效果如下:
大家可以看到,fixed
是相对于浏览器窗口进行固定定位的。
(5)sticky
对于 sticky
来说,就是粘性定位,主要用来做导航栏滑动到一定程度时让导航栏固定到顶部。不过这个属性有它一定的利弊存在,要了解清楚其中存在的各种问题后,谨慎使用!!
这里不再过多介绍,感兴趣的小伙伴可以戳此链接查看该属性的内容~
讲到这里,关于 position
的各种取值解析基本就结束啦!但是细心的小伙伴可能已经发现,上面一直提到的 z-index
,好像都没有讲到。不着急,接下来我们就来讲讲 z-index
这个属性的纸短情长。
🍹三、z-index
1. 一个片面的理解
在我的认知里,一直认为 z-index
是用来描述页面的层叠顺序。一旦 z-index
的值越大,页面就可以叠放的越高。但事实证明,是我孤陋寡闻了。所谓 z-index
,只有在以下场景适用。分别为:
- 首先,
z-index
这个属性并不是在所有的元素上都有效果。它仅仅只在定位元素(定义了position
属性,且属性的值为非static
值的元素)上有效果。 - 要判断元素在
z轴
上的堆叠顺序,并不仅仅是直接比较两个元素的z-index
值的大小,同时,这个堆叠顺序还由元素的层叠上下文和层叠等级共同决定。
先来看一张图👇
相信大家对三维坐标空间一定很熟悉。通常地,我们用 x轴
来表示水平位置,用 y轴
来表示垂直位置,然后用 z轴
来表示在纸面内外方向上的位置。但是呢,由于屏幕是一个二维平面,所以我们并不是真正地看到 z轴
。我们经常说的看到 z轴
,实际上是通过透视,将元素展现在其二维空间的前面或者后面才看到的。
对 z-index
有了一个基础的认识之后,我们来看看它的取值。
2. z-index的取值
要确定沿着这 z轴
元素是如何分布的,css
允许我们对 z-index
属性设置3种类型的值。分别是:
- auto(自动,默认值);
- 整数(正整数/负整数/0);
- inherit(继承)。
目前,让我们先关注在整数值上。 整数值可以是正值,负值,或0。通常来说,数值越大,元素也就越靠近观察者;而数值越小,元素看起来也就越远。
所以,如果有两个元素放在了一起,占据了二维平面上一块共同的区域,那么有着较大 z-index
值的元素就会掩盖或者阻隔有着较低 z-index
值的元素在共同区域的那一部分。
尽管如此,现在还是有一些问题悬而未决、等待我们的解答。具体问题如下:
- 当一个设置了
z-index
值的定位元素与常规文档流中的元素相互重叠的时候,谁会被置于上方? - 当定位元素与浮动元素相互重叠的时候,谁会被置于上方?
- 当定位元素被嵌套在其他定位元素中时,又会发生什么呢?
带着这些问题,我们继续深入了解神奇的 z-index
是怎么工作的,又会抛出哪些新的内容呢?
接下来我们来了解一下上述中提到的层叠上下文、层叠等级和层叠顺序。
3. 层叠上下文
(1)举个例子
我们来做一个具象的比喻:
假设现在有一张桌子,桌子上面呢,放了好多水果,那么这张桌子就代表着一个层叠上下文。
再来,我们还有一张桌子,桌子上面,放了很多本书,那么新的这张桌子,又代表着一个新的层叠上下文。
而水果和书这两样东西,就可以理解为他们所处的层叠上下文中的层叠上下文元素。
这样理解,会不会就明白了许多呢。现在,我们来抛出它的定义。
(2)定义
层叠上下文(stacking context),是HTML中一个三维的概念。在 CSS2.1
规范中,每个盒模型的位置是三维的,分别是平面画布上的X轴
,Y轴
以及表示层叠的Z轴
。一般情况下,元素在页面上沿 X轴
和 Y轴
平铺,我们是察觉不到它们在Z轴
上的层叠关系。而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖。
如果一个元素含有层叠上下文,(也就是说它是层叠上下文元素),我们可以理解为这个元素在Z轴
上就“高人一等”,最终表现就是它离屏幕观察者更近。
4. 层叠等级
(1)定义
讲完层叠上下文,我们再来看看层叠等级又是什么呢?
所谓层叠等级(stacking level),也叫 层叠级别
或 层叠水平
。它有两层含义:
- 在同一个层叠上下文中,它描述的是该层叠上下文中的层叠上下文元素在
Z轴
上的上下顺序。 - 在其他普通元素中,它描述的是这些普通元素在
Z轴
上的上下顺序。
(2)举个例子
同样,我们用刚刚那个例子来继续举例。假设桌子上面的苹果和书,是一层一层叠上去的。
现在,我们先看第一张桌子,第一张桌子的所有苹果,是在同一个层叠上下文中,那么苹果的堆叠顺序,就是在这个层叠上下文中 z轴
上的上下顺序,这是第一层含义。
然后呢,第一张桌子和第二张桌子,他们是两个不同的层叠上下文,我们把它们视为两个普通的元素。那这两个普通的元素,它们也有在 z轴
上的上下顺序。所以呢,这个上下的堆叠顺序,就是我们所说的第二层含义。
5. 形成的条件
看完层叠上下文和层叠等级,我们现在需要来了解一下,要怎么样,才能让元素形成层叠上下文。具体有以下几种情况:
- 根元素
html
; - 绝对定位
ansolute
或相对定位relative
且z-index
值不为auto
; - 一个
flex
项目,且z-index
值不为auto
,也就是父元素display: flex|inline-flex
; - 元素的
opacity
属性值小于1
; - 元素的
transform
属性值不为none
; - 元素的
mix-blend-mode
属性值不为normal
; - 元素的
isolation
属性被设置为isolate
; - 在
mobile WebKit
和Chrome 22+
内核的浏览器中,position: fixed
时总是会创建一个新的层叠上下文, 即使z-index
的值是auto
; - 元素的
-webkit-overflow-scrolling
属性被设置touch
。
6. 层叠顺序
在第 4
点中,尽管上面所说的只包含一个两级的层叠,但事实上在一个层叠上下文中,一共可以有7种层叠等级。具体如下图:
下面我们来一一对上面的7种层叠顺序进行阐述。说明如下:
- 背景和边框 —— 形成层叠上下文的元素的背景和边框,也是层叠上下文中的最低等级。
- 负z-index值 —— 层叠上下文内有着
负z-index值
的子元素。 - 块级盒 —— 文档流中非行内非定位子元素。
- 浮动盒 —— 非定位浮动元素。
- 行内盒 —— 文档流中行内级别非定位子元素。
- z-index: 0 —— 定位元素,这些元素将形成了新的层叠上下文。
- 正z-index值 —— 定位元素。 层叠上下文中的最高等级。
注: 字体颜色对应框内颜色
以上这七个层叠等级构成了层叠次序的规则。比如, 在层叠等级七上的元素会比在等级一至六上的元素显示得更上方(更靠近观察者)。 在层叠等级四上的元素会显示在等级一至三上的元素之上。
看到上面这张图的时候,我想到了一些坑。
如果你只看层叠等级 2
, 6
, 7
(也就是那些提到了 z-index
的等级),那么有很大的可能你会发现这跟你理解的 z-index
可能是一样的。 正 z-index
值比 z-index:0
值更高一层, z-index:0
值又比负 z-index
值高一层。 往往我们很多时候都只理解到了这里,也就觉得 z-index
只有这些内容,往后的事也不了了之了。
但事实上,事实与现实总是不相符的。一般来说,大多数的元素都比 z-index:0
和 z-index > 0
时的层叠等级要低。
另外同样有趣的是非定位元素分散在四个不同的层叠等级上,为什么是这样子的呢?其实,你可以想象以下,如果所有的非定位元素都在同一层叠等级上,那么我们也就不会看到文字(行内盒)在 div
盒子上了(块级盒)。
7. 例子展示
讲到这里,相信大家对 z-index
已经有了一定的认知。接下来呢,我们就就来用一个例子巩固一下上面所学到的知识🌈
先附上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="09.scss">
</head>
<style>
div {
width: 200px;
height: 200px;
padding: 20px;
}
.ele1, .ele2, .ele3, .ele4 {
position: absolute;
}
.ele1 {
background: #38a3a5;
top: 100px;
left: 200px;
z-index: 10;
}
.ele2 {
background: #99d98c;
top: 50px;
left: 75px;
z-index: 100;
}
.ele3 {
background: #57cc99;
top: 125px;
left: 25px;
z-index: 150;
}
.ele4 {
background: #80ed99;
top: 200px;
left: 350px;
z-index: 50;
}
</style>
<body>
<div class="ele1">
1
<div class="ele2">2</div>
<div class="ele3">3</div>
</div>
<div class="ele4">4</div>
</body>
</html>
大家可以先想象一下具体的层叠顺序,然后再来看结果。接下来看一下演示效果:
不知道最终的结果是都跟小伙伴们心里的预期是一样的呢。很多小伙伴可能想着, ele4
的 z-index
值不是 50
吗,而 ele2
和 ele3
的 z-index
值是 100
和 200
,为什么反而是 ele4
在最上面呢。我们来解决这个疑惑。
其实, ele1
和 ele4
是两个不同的层叠上下文,而 ele2
和 ele3
是 ele1
的层叠上下文元素。所以, ele1
的值是 10
,而 ele2
和 ele3
可以理解为是 10.100
和 10.150
,这样,自然地,ele4
肯定就是在最上方了。
还有另外一种特殊情况就是, ele4
的 z-index
的值跟 ele1
的值是一样的,都是 10
。在这种情况下,如果遇到在同一个层叠上下文的元素,他们的 z-index
值如果一样的话,那得遵循个先来后到原则。 ele1
先出现了,所以它在里面;而 ele4
后出现,它在外面。
那如果遇到 ele4
的 z-index
的值是 9
呢?我们改一下 ele4
的 css
样式,然后来观察一下效果。具体代码如下:
.ele4 {
background: #80ed99;
top: 200px;
z-index: 9;
}
具体效果如下:
通过上图,大家可以发现,ele4
的 z-index
值比 ele1
小,所以自然地, ele4
在里面, ele1
在外面。
🥂四、结束语
当你初次遇到 z-index
时,它就像一个非常简单、易于理解的属性。 它的值代表着在朝向屏幕内外面轴上的位置。而深入探究 z-index
以后我们还发现了很多 z-index
背后的事情, 包括层叠上下文、层叠等级和层叠次序规则等等。
所以说呀,万宗不变其一,万事万物还是得追溯到源头上才能更好的解决问题本身。
相信通过上文的了解,大家对 position
和 z-index
又有了一个全新的认识~
🐣彩蛋 One More Thing
(:参考资料
长安曹公子👉彻底搞懂CSS层叠上下文、层叠等级、层叠顺序、z-index
Steven Bradley👉关于z-index 那些你不知道的事
猫儿不熊👉CSS-position:static/relative/absolute/fixed定位
书籍👉张鑫旭老师的CSS世界
(:番外篇
关注公众号星期一研究室,第一时间关注优质文章,更多精选专栏待你解锁~
如果这篇文章对你有用,记得留个脚印jio再走哦~
以上就是本文的全部内容!我们下期见!👋👋👋