# 蜜汁定位

# 定位常见值及原理
position 属性用来指定一个元素在网页上的位置,一共有5种定位方式,即 position 属性主要有五个值
- static (默认值)
- relative (相对定位)
- absolute (绝对定位)
- fixed (固定定位)
- sticky (粘连定位)
static 默认值
static是 position 属性的默认值。如果省略 position 属性,浏览器就认为该元素是static定位。这时浏览器会按照源码的顺序,决定每个元素的位置,这称为"正常的页面流"(normal flow)。每个块级元素占据自己的区块(block),元素与元素之间不产生重叠,这个位置就是元素的默认位置。该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left和 z-index 属性无效。
relative 相对定位
表示,相对于默认位置(即static时的位置)进行偏移,定位基点是元素的默认位置,它必须搭配top、bottom、left、right这四个属性一起使用,用来指定偏移的方向和距离。
absolute 绝对定位
表示,相对于上级元素(一般是父元素)进行偏移,即定位基点是父元素。它有一个重要的限制条件:定位基点(一般是父元素)不能是static定位,否则定位基点就会变成整个网页的根元素html。另外,absolute 定位也必须搭配 top、bottom、left、right 这四个属性一起使用。注意,absolute 定位的元素会被"正常页面流"忽略,即在"正常页面流"中,该元素所占空间为零,周边元素不受影响。
fixed 固定定位
表示,相对于视口(viewport,浏览器窗口)进行偏移,即定位基点是浏览器窗口。这会导致元素的位置不随页面滚动而变化,好像固定在网页上一样。它如果搭配top、bottom、left、right 这四个属性一起使用,表示元素的初始位置是基于视口计算的,否则初始位置就是元素的默认位置。
sticky 粘连定位 (top、bottom、left、right必须都要有)
跟前面四个属性值都不一样,它会产生动态效果,很像relative和fixed的结合:一些时候是relative定位(定位基点是自身默认位置),另一些时候自动变成fixed定位(定位基点是视口)。因此,它能够形成"动态固定"的效果。比如,网页的搜索工具栏,初始加载时在自己的默认位置(relative定位)。sticky生效的前提是,必须搭配top、bottom、left、right这四个属性一起使用,不能省略, 否则等同于relative定位,不产生"动态固定"的效果。原因是这四个属性用来定义"偏移距离",浏览器把它当作 sticky 的生效门槛。它的具体规则是,当页面滚动,父元素开始脱离视口时(即部分不可见),只要与sticky元素的距离达到生效门槛,relative定位自动切换为fixed定位;等到父元素完全脱离视口时(即完全不可见),fixed定位自动切换回relative定位; 页面向下滚动时,工具栏变成固定位置,始终停留在页面头部(fixed定位);等到页面重新向上滚动回到原位,工具栏也会回到默认位置。 除了已被淘汰的IE 以外,其他浏览器目前都支持sticky。但是,Safari 浏览器需要加上浏览器前缀-webkit-;
position: -webkit-sticky; /* safari 浏览器 */
position:sticky; /* 其他浏览器 */
2

# postition: fixed 和 sticky
position:sticky 粘性定位与position:fixed固定定位; 都可以在拖动滚动条的时候,将元素固定于指定位置,但是两者的区别也是非常巨大的。
position: fixed
- 元素可以被固定于页面指定位置,始终固定于此位置。
- 定位位置可以通过 top、bottom、left与right属性设置。
- 如果属性同时设置,那么top的优先级高于bottom,left的优先级高于right。
- top、bottom、left与right无需显式设置,fixed 定位也会生效。
- 元素的定位参考对象是当前窗口。
- 元素脱离文档流。
- 当前所有主流浏览器都支持此定位方式(不再考虑IE6浏览器)
position: fixed 的特殊性
正常情况下,固定定位是相对于浏览器视窗(viewport)进行定位的,但是当其祖先元素中存在符合以下任意一个条件的元素时,固定定位元素会相对于该元素进行定位:
- 1、transform 属性值不为 none
- 2、transform-style: preserve-3d
- 3、perspective 属性值不为 none
- 4、will-change 属性 指定了上面 3 个 CSS 属性中的任意一个

position:sticky
- 元素可以被固定于页面指定位置,但并不一定始终固定于此位置。
- 定位位置可以通过top、bottom、left与right属性设置,但是此位置是一个临界值,也就是说元素只有达到设置的这个临界值才会固定,其他位置并不会固定。
- 如果属性同时设置,那么top的优先级高于bottom,left的优先级高于right。
- 必须至少显式设置top、bottom、left与right其中某一个属性值,sticky定位才会生效。
- 元素的定位参考对象距离其最近的 overflow 属性值为 visible 的具有滚动条的祖先元素,如果是以body或者body的父辈元素为考,那么定位参考对象是窗口。
- 元素不会脱离文档流。
- 浏览器兼行当前有点差,Safari目前还需要-webkit-私有前缀。

# 层叠上下文和层叠顺序
- 什么叫层叠上下文?
层叠上下文(stacking context),是HTML中一个三维的概念。在CSS2.1规范中,每个盒模型的位置是三维的,分别是平面画布上的X轴,Y轴以及表示层叠的Z轴。一般情况下,元素在页面上沿X轴Y轴平铺,我们察觉不到它们在Z轴上的层叠关系。而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖。如果一个元素含有层叠上下文,(也就是说它是层叠上下文元素),我们可以理解为这个元素在Z轴上就“高人一等”,最终表现就是它离屏幕观察者更近。

- 层叠上下文具象理解:
层叠上下文是一个概念,跟【块状格式化上下文(BFC)】类似。然而,概念这个东西是比较虚比较抽象的。 可以把【层叠上下文】理解为当官:网页中有很多很多的元素,我们可以看成是真实世界的芸芸众生。真实世界里,我们大多数人是普通老百姓,还有一个部分人是做官的官员。这里的‘官员’ 就可以理解为网页中的层叠上下文元素。换句话说,页面中的元素有了层叠上下文,就好比我们普通老百姓当了官,一旦当了官,相比普通百姓而言,离皇帝就更近了,就等同于网页中元素级别更高了,离我们用户就更近了。
- 层叠等级含义:
层叠等级(stacking level,叫“层叠级别”/“层叠水平”也行),在同一个层叠上下文中,它描述定义的是该层叠上下文中的层叠上下文元素在Z轴上的上下顺序。在其他普通元素中,它描述定义的是这些普通元素在Z轴上的上下顺序;
- 总结:
普通元素的层叠等级优先由其所在的层叠上下文决定。
层叠等级的比较只有在当前层叠上下文元素中才有意义。不同层叠上下文中比较层叠等级是没有意义的。
- 层叠顺序
"层叠顺序" (stacking order)表示元素发生层叠时按照特定的顺序规则在Z轴上垂直显示。由此可见,前面所说的“层叠上下文”和“层叠等级”是一种概念,而这里的“层叠顺序”是一种规则。

同一个堆叠上下文元素在Z轴的排列:
- 创建推叠上下文的元素的背景和边框
- 堆叠级别(z-index,stack level)为负值的堆叠上下文
- 常规流非定位的块盒 (块元素)
- 非定位的浮动盒子 (浮动元素)
- 常规流非定位行盒 (行内元素)
- 任何z-index是auto的定位子元素,以及z-index是0的堆叠上下文
- 堆叠等级为正值的堆叠上下文
通俗理解:
- 当两个元素类型一样时,默认情况下后一个元素层级比前一个元素层级高。
- 在没有设置背景的情况下,元素的背景是透明的,并且允许后面的元素透上来。
- 块元素和其他任意除定位元素以外,文字层级比背景层级高。
- 浮动和块元素,浮动层级高。
- 浮动和行内块,行内块层级高。
- 浮动和行内,行内层级高。
- 定位和定位,后一个元素层级高。
- 定位比所有元素层级高。

/*
html 根层叠上下文
层叠上下文的元素 - html
层叠顺序:
背景或边框 < z-index负值 <
块级元素 < 浮动元素 < 行内、行内块元素 < position z-index:auto/0
< position z-index正值
*/
html{
/* 根元素 */
background-color: red;
}
/* 块级元素 div*/
.box{
width: 200px;
height: 200px;
background-color: green;
}
/* 浮动元素 */
.box1{
width: 200px;
height: 200px;
background-color: gold;
float: left;
margin-left: 10px;
margin-top: -30px;
}
/* 行内、行内块元素 */
.box2{
display: inline-block;
width: 300px;
height: 300px;
background-color: blue;
margin-left: -100px;
}
.box3{
width: 300px;
height: 300px;
background-color: green;
position: relative;
top: -100px;
}
.box4{
width: 300px;
height: 300px;
background-color: orange;
position: relative;
z-index: 1;
top: -200px;
left: 100px;
}
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
<div class="box">块元素</div>
<div class="box1">浮动元素</div>
<div class="box2">行内</div>
<div class="box3">相对定位 没有设置z-index</div>
<div class="box4">z-index 正值</div>
2
3
4
5
(同一个层叠上下文最重要的图!!!)

层叠准则:
- 谁大谁上:当具有明显的层叠水平标示的时候,如识别的z-indx值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。通俗讲就是官大的压死官小的。
- 后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在 DOM 流中处于后面的元素会覆盖前面的元素。
层叠上下文的特点:
- 层叠上下文的层叠水平要比普通元素高
- 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的层叠上下文
- 每个层叠上下文和兄弟元素独立,也就是当进行层叠变化或渲染的时候,只需要考虑后代元素
- 每个层叠上下文都是自成体系的,当一个元素内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层叠
# 层叠上下文形成条件
文档中的层叠上下文由满足以下任意一个条件的元素形成:
- 根层叠上下文: 页面根元素天生具有层叠上下文,称之为“根层叠上下文”( <html>)
- 定位元素与传统层叠上下文:z-index 值为数值的定位元素的传统层叠上下文
- CSS3 中新属性也可以产生层叠上下文:
- z-index 值不为 auto 的 flex 项(父元素 display: flex | inline-flex)
- 元素的 opacity 值不是 1
- 元素的 transform 值不是 none
- 元素的 mix-blend-mode 值不是 normal
- 元素的 filter 值不是 none
- 元素的 isolation 值是 isolate
- will-change 指定的属性值为上面任意一个
- 元素的 -webkit-overflow-scrolling 设为 touch
z-index: auto | 0
<!-- 案例解析一 -->
<div style="position:relative; z-index:auto;">
<img src="images/mm1.jpg" style="position:absolute; z-index:2;">
</div>
<div style="position:relative; z-index:auto;">
<img src="images/mm2.jpg" style="position:relative; z-index:1;">
</div>
<hr>
<!-- 案例解析一 -->
<div style="position:relative; z-index:0;">
<img src="images/mm1.jpg" style="position:absolute; z-index:2;">
</div>
<div style="position:relative; z-index:0;">
<img src="images/mm2.jpg" style="position:relative; z-index:1;">
</div>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

父元素 display: flex
<!-- 案例一分解:display:flex/inline-flex; -->
<div class="box">
<div class="parent">
parent
<div class="child">child</div>
</div>
</div>
2
3
4
5
6
7
/*
层叠上下文元素:
html、child + parent
parent 其实就是一个普通的块元素
块元素 > 定位 z-index:-1
*/
.box{
display: flex;
}
.parent{
width: 200px;
height: 100px;
background: #168bf5;
z-index: 1;
}
.child{
width: 100px;
height: 200px;
margin-top: -20px;
background: #32d19c;
position: relative;
z-index: -1;
text-align: right;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

opacity
<div class="parent1">
parent
<div class="child1">child</div>
</div>
2
3
4
.parent1{
width: 200px;
height: 100px;
background: #168bf5;
opacity: .5;
}
.child1{
width: 100px;
height: 200px;
background: #32d19c;
position: relative;
z-index: -1;
}
2
3
4
5
6
7
8
9
10
11
12
13

transform
<div class="parent3">
parent
<div class="child3">child</div>
</div>
2
3
4
.parent3{
width: 200px;
height: 100px;
background: #168bf5;
transform: rotate(5deg);
}
.child3{
width: 100px;
height: 200px;
background: #32d19c;
position: relative;
z-index: -1;
}
2
3
4
5
6
7
8
9
10
11
12
13

filter
<div class="parent4">
parent
<div class="child4">child</div>
</div>
2
3
4
.parent4{
width: 200px;
height: 100px;
background: #168bf5;
filter: blur(5px);
}
.child4{
width: 100px;
height: 200px;
background: #32d19c;
position: relative;
z-index: -1;
}
2
3
4
5
6
7
8
9
10
11
12
13

# 层叠上下文对z-index的影响
z-index属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。该属性设置一个定位元素沿 z 轴的位置,z 轴定义为垂直延伸到显示区的轴。如果为正数,则离用户更近,为负数则表示离用户更远
- 层叠上下文(stacking context)并不只是 z-index(必须配合position才能生效)才能创建,还有很多其他元素(如:opacity、transform等)也可以创建层叠上下文
- 在存在层叠上下文的情况下,z-index 的大小决定了层叠水平(stacking level),即谁在谁上面,这是“谁大谁上”原则
- 层叠水平的比较只有在同一级别的 DOM 节点的层叠上下文中才有意义
- 在同一DOM节点,并且层级水平一样的情况下,在HTML文档中写在后面的元素会遮住前面的元素(后者会在前者上面),这是"后来居上" 原则

- 参考