前言
写网页很像安排一场舞台演出:有人按照队伍依次登场,有人需要从原位挪开一点,有人要直接站到舞台中央,还有人无论页面怎样滚动,都要守在屏幕边缘。
CSS 定位布局解决的就是"元素应该出现在哪里"这个问题。要真正理解它,不必急着背属性,而要先弄清三个关键点:元素原本怎样排列、定位时以谁为参照、移动后是否还占据原来的空间。
一、文档流
浏览器在没有特殊布局规则时,页面布局默认是按从上往下,从左往右的排列,呈现一种流式的排列,并且会按照 HTML 元素出现的先后顺序排列内容。这种默认的排列秩序叫作文档流。
可以把页面想象成一条井然有序的队伍:
- 块级元素通常从上到下排列,一个接一个;
- 行内内容通常从左到右排列,一行放不下时再换到下一行;
- 前面的元素占据多少空间,会直接影响后面元素的位置。
文档流的价值在于,它让页面具有自然的伸缩能力。文字变多时,容器会被撑开;某个模块变高时,后面的内容会自动向下移动。开发者不需要为每个元素计算精确坐标,浏览器就能完成大部分基础排版。
什么是脱离文档流
如果一个元素脱离文档流,其他元素在排版时就会忽略它原本占据的空间。
这就像一个人离开了正在排队的队伍:他仍然可能站在大家看得见的地方,但后面的人已经向前补位,不会继续为他留出位置。因此,脱离文档流的元素很容易与其他内容发生重叠。
判断一种布局方式时,可以先问两个问题:
- 元素移动后,原来的位置是否还被保留?
- 后面的元素是否仍然需要为它让出空间?
只要把这两个问题想清楚,后面的定位概念就会容易很多。
1. 块级元素:一个人占一排
块级元素通常会独占一行。即使它本身没有占满整行,后面的块级元素一般也会从下一行开始排列。
它的主要特点包括:
- 通常从上到下排列;
- 可以直接设置宽度和高度;
- 没有指定宽度时,通常会尽可能占满父容器的可用宽度;
- 很适合构建页面中的大块结构。
常见的块级标签有 div、p 和 h1。它们默认会从新的一行开始,适合搭建页面结构或承载大块内容。
可以把块级元素想成一位包下整排座位的观众:他自己可能只坐在其中一小块区域,但下一位观众仍然要去下一排。
2. 行内元素:跟着文字一起走
行内元素不会主动独占一行,而是像句子中的文字一样,从左到右连续排列。只有当前行空间不足时,它们才会自然换行。
它的主要特点包括:
- 可以与其他行内内容出现在同一行;
- 占据的空间通常由自身内容决定;
- 普通情况下,不能像块级元素那样直接控制宽度和高度;
- 很适合表示文字中的局部内容。
常见的行内标签有 span、a 和 strong。它们适合嵌入句子内部,不会因为自身出现就强制换行。
行内元素就像坐在同一排长椅上的人:每个人只占自己需要的位置,只要长椅还有空间,后来的人就可以继续坐在旁边。
3. 行内块元素:既能同排,又能控制尺寸
行内块元素结合了前两种类型的部分特点。它在排列方式上像行内元素,可以和其他元素待在同一行;在尺寸控制上又像块级元素,可以设置明确的宽度和高度。
它的主要特点包括:
- 不会默认独占一整行;
- 可以控制宽度和高度;
- 可以在同一行放置多个尺寸明确的元素;
- 适合制作按钮、标签和横向导航项。
button、input 和 select 等表单控件通常具有类似行内块元素的表现,既能在同一行排列,也可以控制尺寸。
如果说块级元素是"一人一排",行内元素是"大家挤在长椅上",那么行内块元素就像一排尺寸固定的独立座椅:每个座位大小明确,又能整齐地排在同一行。
三种类型可以这样对比:
| 元素类型 | 是否通常独占一行 | 能否直接控制宽高 |
|---|---|---|
| 块级元素 | 是 | 可以 |
| 行内元素 | 否 | 通常不可以 |
| 行内块元素 | 否 | 可以 |
需要注意的是,元素类型主要决定它在文档流中如何排列;定位布局则进一步决定它能否偏离原位置、以谁为参照以及是否脱离文档流。两者相互配合,但不是同一个概念。
标签的默认显示类型也可以通过 CSS 中的 display 改变,如:
css
display: block; //表示设置为块级元素
display: inline; //表示设置为行内元素
display: inline-block; //表示设置为行内块元素
因此应以元素当前的显示方式判断它如何参与布局。
二、四大定位布局类型
CSS 中常见的定位方式包括相对定位、绝对定位、固定定位和黏性定位。理解它们时,不要只记名称,而要同时观察三个维度:参照物、文档流和使用场景。
1. 相对定位:从自己的座位挪一下
position: relative;相对定位以元素原本在文档流中的位置作为参照。元素可以从原位置向上、向下、向左或向右偏移。以下面的HTML代码为例:
html
<style>
*{
margin: 0;
}
.box1{
width: 100px;
height: 100px;
background-color: #e237cb;
position: relative; //设置为相对布局
/* 相对在原本的文档流的位置进行偏移 */
left: 200px; // 向右偏移200px
top: 100px; // 向下偏移100px
}
.box2{
width: 200px;
height: 200px;
background-color: #252577;
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
</body>

我们已知 box1 和 box2 为都为div块级元素,应占据一整行,然后我们将box1设置为定位布局后, box1所代表的紫色色块分别向右和下进行的移动,但也可以看到,其所原本占据的文档流位置仍存在。
这也是定位布局最鲜明的特点:元素虽然在视觉上移动了,但原来占据的空间仍然保留。后面的元素依旧按照它移动前的位置进行排列。即相对定位不会导致脱离文档流。
这就像一个人从自己的座位旁边站了起来:别人能看到他的位置发生了变化,但他的座位仍然被占着,其他人不能坐进去。
相对定位通常有两类用途:
- 对元素进行小范围的位置微调;
- 为内部的绝对定位元素建立一个明确的参照范围。
第二种用途尤其常见,我将在"绝对定位这部分"举例。很多时候,父元素开启相对定位并不是为了移动自己,而是为了告诉子元素:"如果你要绝对定位,就以我为参照。"
2. 绝对定位:离开队伍,在指定房间找坐标
绝对定位会使元素脱离文档流。其他元素排版时不再为它保留位置,因此它可能覆盖在普通内容上方,也可能被其他元素覆盖。以下面的HTML代码为例:
html
<style>
.box{
width: 300px;
height: 300px;
border: 2px solid #000;
position: relative; // 开启定位
}
.wrapper{
background-color: #8d1e80;
position: absolute; //设置为绝对定位
left: 50%; //相对 "box" ,向右偏移 "box" 的50%宽度
top: 50%; //相对 "box" ,向下偏移 "box" 的5高度
transform: translate(-50%, -50%) //相对 "wrapper"自身 ,向右和向下偏移自身的50%宽高
}
</style>
<div class="box">
<div class="wrapper">hello</div>
<div class="name">zmjjkk</div>
</div>
<h2>标题</h2>

绝对定位不会简单地以自己原来的位置为参照。它会向外寻找最近的、已经开启定位的祖先元素(这个例子中我们将 wrapper 和 name 的父亲元素 box 设置成了相对定位)并以这个祖先作为定位范围。如果找不到合适的定位祖先,它通常会以 body 作为参照。
并且会脱离原来的文档流 ,所以我们可以看到wrapper和name都是块级元素,本来应该到wrapper和name各占据box中的一行并且wrapper应该在name的上面,但现在是wrapper占据了原本name的位置。
可以把它想成一名拿到特殊通行证的演员:他不再跟随普通队伍上场,而是在指定舞台中按照坐标直接就位。舞台由哪个父元素提供,取决于最近的定位祖先是谁。
绝对定位适合以下场景:
- 容器角落的提示角标;
- 图片上的文字或按钮;
- 弹窗内部的关闭按钮;
- 局部区域中的精确居中与覆盖效果。
它不适合承担整页的常规排版。因为元素一旦大量脱离文档流,内容变化时就很难自动推开彼此,页面容易出现重叠和错位。
3. 固定定位:钉在浏览器窗口上
固定定位通常以浏览器可视区域作为参照,并且会脱离文档流。
页面滚动时,普通内容会跟随页面移动,而固定定位元素在视口中的位置通常保持不变。它像一张贴在浏览器玻璃上的便签:玻璃后面的页面可以滚动,便签却一直停留在眼前。如下面的HTML所示:
html
<style>
body{
height: 1000px;
}
.box{
width: 100px;
height: 100px;
background-color: red;
position: fixed; //设置为固定定位
bottom: 10px; // 距离底部10px
right: 10px; // 距离最右边10px
}
</style>
<body>
<div class="box"></div>
<h2>hello</h2>
</body>

固定定位常用于:
- 返回顶部按钮;
- 悬浮客服入口;
- 始终可见的顶部或底部工具栏;
- 覆盖整个屏幕的遮罩层。
使用固定定位时,需要特别注意内容遮挡问题。因为它已经脱离文档流,其他内容不会主动为它腾出空间。桌面端看起来大小合适的悬浮元素,在手机屏幕上可能会挡住正文或操作按钮。
4. 黏性定位:先随队伍移动,到线后吸住
黏性定位可以理解为相对定位 和固定定位的结合。
在元素还没有滚动到指定边界时,它会跟随页面正常移动;当它即将越过设定的吸附位置时,就会暂时停留在滚动区域的边缘;当所属容器的边界到来后,它又会受到容器范围的限制。 如下面的HTML代码所示:
htMl
<style>
body{
height: 200vh;
}
.box1{
width: 500px;
height: 500px;
background-color: rgb(172, 106, 159);
}
.box2{
height: 100px;
background-color: aqua;
position: sticky; //设置为黏性定位
top: 0; //当这个元素滚动到距离滚动容器顶部 0px 的位置时,就不要再继续往上滚了,黏在这里
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
</body>

它就像一块放在白板上的磁铁:平时跟着白板一起移动,碰到指定边缘时会暂时吸住,但它始终不能脱离自己所在的白板。
黏性定位通常不会脱离文档流,原本占据的空间会继续保留,因此非常适合制作:
- 吸顶导航;
- 文章中的章节标题;
- 通讯录中的分组名称;
- 长表格中需要持续显示的表头。
最后,用一张表概括四种定位方式:
| 定位方式 | 主要参照物 | 是否脱离文档流 | 核心印象 |
|---|---|---|---|
| 相对定位 | 自己原本的位置 | 否 | 人挪走了,座位还在 |
| 绝对定位 | 最近的定位祖先 | 是 | 离开队伍,在指定房间找坐标 |
| 固定定位 | 浏览器可视区域 | 是 | 钉在浏览器窗口上 |
| 黏性定位 | 滚动区域与所属容器 | 否 | 先随页面移动,到线后吸住 |
三、定位元素重叠时:理解 z-index
元素发生定位后,很容易出现互相重叠。此时除了"放在哪里",还需要决定"谁显示在上面"。这就是层叠顺序要解决的问题。
通常情况下,层级数值越大的元素越靠近观察者。不过,把它简单理解为"数字大的一定在上面"并不准确,因为层级比较受到层叠上下文限制。
层叠上下文可以想象成一栋栋独立的大楼。子元素只能先在自己的大楼内部排楼层,而两栋大楼谁在前面,要先看大楼本身的顺序。即使某个子元素在自己楼里住在一万层,也不一定能盖住另一栋整体位于前方的大楼。
理解层叠顺序时,可以记住以下几点:
- 元素重叠且没有额外设置层级时,下面的标签比上面的标签优先级更高,后面的会盖住前面的。
- 层级z-index要生效,必须要配合定位属性position
- 层级只能在兄弟元素之间相比较,自己的子元素与兄弟元素的层级无法相比较;