CSS 定位
position 属性控制元素在页面上的定位方式。CSS 提供了五种定位模式,各有不同的参照系和行为。
五种定位模式速览
| 值 | 参照系 | 脱离文档流 | 典型用途 |
|---|---|---|---|
static | —(默认流) | 否 | 常规布局(默认值) |
relative | 元素自身原本位置 | 否 | 微调位置,为绝对定位设置参照 |
absolute | 最近的非 static 祖先 | 是 | 弹窗、下拉菜单、覆盖层 |
fixed | 视口(浏览器窗口) | 是 | 固定导航栏、浮动按钮、模态框 |
sticky | 滚动容器 | 否/是 | 吸顶导航、表格固定表头 |
position: static — 默认值
所有元素默认为 static。它遵循正常的文档流,top/right/bottom/left 和 z-index 对它无效。
div {
position: static; /* 默认值,通常不需要显式写 */
} position: relative — 相对定位
相对于元素原本的位置进行偏移,不脱离文档流(原位置保留空白):
.adjust {
position: relative;
top: -4px; /* 向上偏移 4px */
left: 10px; /* 向右偏移 10px */
} relative 最常用的场景不是偏移自身,而是作为子元素 absolute 定位的参照容器:
.parent {
position: relative; /* 为子元素创建定位上下文 */
}
.child {
position: absolute;
top: 0;
right: 0; /* 位于父元素右上角 */
} <div class="parent" style="width:300px;height:100px;background:#f1f5f9;border:2px solid #e2e8f0">
<div class="child" style="background:#2563eb;color:white;padding:4px 8px">右上角</div>
</div> 一个常见的 bug:absolute 定位的子元素”飞到了页面左上角”。这是因为它的父元素、祖先元素都没有 position: relative(或 absolute/fixed),导致子元素相对于 <body> 定位。给父元素加 position: relative(不改动布局)即可解决。
position: absolute — 绝对定位
相对于最近的非 static 祖先元素定位,脱离文档流(不占空间):
/* 右上角的角标 */
.card {
position: relative; /* 创建定位上下文 */
}
.badge {
position: absolute;
top: -8px;
right: -8px;
background: #ef4444;
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.75rem;
}
/* 居中对齐(绝对定位 + transform) */
.modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* 向左、向上各移动自身宽高的一半,实现精确居中 */
} 如果没有定位祖先,absolute 元素会相对于 <html> 或 <body> 定位。
position: fixed — 固定定位
相对于浏览器视口定位,脱离文档流。滚动页面时,元素固定在屏幕上的不变位置:
/* 固定顶部导航栏 */
.topbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: white;
z-index: 100;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
/* 右下角浮动按钮 */
.fab {
position: fixed;
bottom: 24px;
right: 24px;
width: 56px;
height: 56px;
border-radius: 50%;
background: #2563eb;
color: white;
} position: fixed 的参照系通常是视口,但如果父元素有 transform、perspective 或 filter 属性,fixed 会退化(相对于该父元素定位而非视口)。这是 CSS 的一个反直觉行为。
position: sticky — 粘性定位
sticky 是 relative 和 fixed 的混合体——在滚动到临界点前像 relative,到达临界点后像 fixed:
/* 吸顶导航 */
.section-header {
position: sticky;
top: 0; /* 当元素顶部到达视口顶部时开始固定 */
background: white;
z-index: 10;
}
/* 表格固定表头 */
thead th {
position: sticky;
top: 0;
background: #f8fafc;
} sticky 的几个前提:必须设置 top/right/bottom/left 中的至少一个(否则与 relative 无异);父元素不能设 overflow: hidden(否则 sticky 失效,因为滚动容器变成父元素);父元素高度必须大于 sticky 元素(否则不需滚动就可见全部内容)。
z-index — 叠放顺序
当多个定位元素重叠时,z-index 决定谁在上方:
.layer1 { z-index: 1; } /* 下层 */
.layer2 { z-index: 2; } /* 中层 */
.layer3 { z-index: 10; } /* 最上层 */ <div style="position:relative;height:120px">
<div class="layer1" style="position:absolute;top:0;left:0;width:120px;height:120px;background:#93c5fd">z-index: 1</div>
<div class="layer2" style="position:absolute;top:20px;left:20px;width:120px;height:120px;background:#60a5fa">z-index: 2</div>
<div class="layer3" style="position:absolute;top:40px;left:40px;width:120px;height:120px;background:#2563eb;color:white">z-index: 10</div>
</div> z-index 只对定位元素(position 不是 static)和 flex/grid 子元素生效。普通的 static 元素设置 z-index 无效。此外 z-index 受层叠上下文影响——拥有对比属性的定位元素会创建独立的 z-index 作用域。
常用场景汇总
| 需求 | 方案 |
|---|---|
| 卡片右上角的”新品”角标 | 父 relative + 子 absolute |
| 固定在顶部的导航栏 | fixed + top: 0 |
| 固定在右下角的按钮 | fixed + bottom + right |
| 滚动列表的分组标题吸顶 | sticky + top |
| 模态弹窗居中 | fixed + top: 0; right: 0; bottom: 0; left: 0(或简写 inset: 0) + flex/grid 居中 |
| 拉到最底部时出现的加载更多 | sticky + bottom: 0 |