大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
定位
这一课你将能做到
- 说出 static、relative、absolute、fixed、sticky 五种定位的差异
- 用 relative + absolute 实现「父相子绝」布局
- 用 z-index 控制层叠顺序,理解层叠上下文
- 用 fixed 做吸顶导航,用 sticky 做滚动吸附
为什么要学
正常文档流是「从上到下、从左到右」,但实际页面有大量「脱离正常流」的需求:弹窗浮在所有内容上面、导航栏吸顶、返回顶部按钮钉在右下角。这些都靠 position 实现。
人话:position 决定元素是「跟着大部队排队」还是「脱离队伍自由漂浮」——absolute 像贴在某个祖先上的便利贴,fixed 像粘在屏幕上的图钉,sticky 像走到天花板就停下的气球。
先建立图像
<style>
body { height: 200vh; padding-top: 100px; } /* 让页面可滚动 */
.parent {
position: relative;
width: 300px; height: 200px;
background: #f0f0f0;
}
.child {
position: absolute;
top: 20px; right: 20px;
background: tomato; color: #fff;
padding: 8px;
}
.fixed-btn {
position: fixed;
bottom: 30px; right: 30px;
background: #0366d6; color: #fff;
padding: 12px 20px; border-radius: 50%;
}
</style>
<div class="parent">
父容器(relative)
<div class="child">absolute 子元素</div>
</div>
<button class="fixed-btn">回到顶部</button>
absolute 子元素相对父容器定位;fixed 按钮粘在屏幕右下,滚动页面不动。
跟着做
步骤 1:static(默认值)
.box { position: static; }
正常文档流,top/right/bottom/left/z-index 全部无效。这是所有元素的初始状态。
步骤 2:relative 相对定位
.box {
position: relative;
top: 20px; /* 在原位置基础上向下 20px */
left: 30px; /* 在原位置基础上向右 30px */
}
关键点:元素仍占据原来的空间,只是视觉上偏移了。其他元素不会填补它的位置。
<p>第一段</p>
<p style="position: relative; top: 10px; background: yellow;">第二段(下移 10px)</p>
<p>第三段</p>
第二段视觉上下移,但第三段位置不变,因为第二段的「坑位」还在。
步骤 3:absolute 绝对定位
.child {
position: absolute;
top: 0; right: 0;
}
关键点:元素脱离正常文档流,不占据空间;定位参照是「最近的非 static 祖先」;如果所有祖先都是 static,参照 <body>。
经典「父相子绝」:
.card {
position: relative; /* 父元素建立定位参照 */
}
.badge {
position: absolute;
top: -8px; right: -8px; /* 角标超出卡片 */
background: red;
color: #fff;
border-radius: 50%;
width: 24px; height: 24px;
}
步骤 4:fixed 固定定位
.navbar {
position: fixed;
top: 0; left: 0; right: 0;
height: 60px;
background: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
参照视口,滚动不影响它。常做吸顶导航、底部工具栏、回到顶部按钮。
注意:父级有 transform、filter、perspective 时,fixed 会失效(变成相对该父级定位)。
步骤 5:sticky 粘性定位
.section-title {
position: sticky;
top: 0; /* 滚动到距顶部 0 时粘住 */
background: #fff;
padding: 10px;
}
元素在正常流中,滚动到阈值时「粘住」,超过父容器范围又继续滚走。适合做「分组标题」:滚动列表时当前分组标题吸顶。
<div class="group">
<h3 class="section-title">A 组</h3>
<p>很多内容...</p>
</div>
<div class="group">
<h3 class="section-title">B 组</h3>
<p>很多内容...</p>
</div>
步骤 6:z-index 控制层叠
.modal { position: fixed; z-index: 1000; }
.tooltip { position: absolute; z-index: 2000; }
.navbar { position: fixed; z-index: 100; }
z-index 只对定位元素(非 static)生效。数字越大越靠前。
步骤 7:层叠上下文(stacking context)
z-index 不是全局比较,而是在同一个层叠上下文内比较。以下属性会创建新的层叠上下文:
position: absolute/relative/fixed/sticky+z-index非 autoopacity < 1transform非 nonefilter非 none- flex/grid 子元素的 z-index
<div style="position: relative; z-index: 1;">
<div style="position: absolute; z-index: 9999;">A</div>
</div>
<div style="position: relative; z-index: 2;">
<div style="position: absolute; z-index: 1;">B</div>
</div>
A 的 z-index 9999 比 B 的 1 大,但 A 的父层叠上下文 z-index 是 1,B 的父是 2,所以 B 在 A 上面。
讲清楚要点
- absolute 找最近的非 static 祖先:找不到就用 body。所以「父相子绝」是惯例。
- fixed 相对视口:但有 transform/filter 的祖先会让它失效。
- sticky 是「相对 + 固定」的混合:在容器内相对、滚动到阈值时固定。
- z-index 不是越大越好:要在同一层叠上下文里比较,9999 不一定赢 1。
- relative 不脱离文档流:原本的坑位还在;absolute 完全脱离,坑位被后来者填上。
你可能会懵的地方
-
absolute 元素宽怎么定? 默认收缩到内容宽度。想撑满父容器:
left: 0; right: 0;或width: 100%。 -
sticky 不生效的常见原因? 父元素有
overflow: hidden/auto/scroll;或父元素高度不够;或没设阈值(top/right/bottom/left)。 -
fixed 在移动端键盘弹出时乱跑? iOS 老 Bug。解决方案:用 absolute + 监听 scroll,或用
env(keyboard-inset-height)。 -
z-index 设了 9999 还是不显示? 父元素的层叠上下文限制了它。检查父元素是否有 transform、opacity < 1 等。
-
top 和 margin-top 区别? top 是视觉偏移(不影响邻居),margin-top 是真实占位(影响邻居)。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
position: absolute 但父级全是 static | 相对 body 定位 | 父级加 position: relative |
| 给 fixed 设了 transform 父级 | fixed 失效 | 移掉父级 transform |
sticky 父级 overflow: hidden | sticky 失效 | 移除 overflow 或换结构 |
| z-index 设 999999 | 没意义且难以维护 | 用 1、10、100、1000 等级别 |
| 用 absolute 做整体布局 | 内容变化时全部错位 | 主布局用 flex/grid,absolute 只做角标/弹层 |
卡点急救
- 元素跑偏到 body:检查父级是否有非 static 定位。
- z-index 不生效:元素必须是定位元素(非 static);检查层叠上下文。
- sticky 完全不粘:检查父级 overflow 和高度。
面试常问
-
absolute 和 fixed 区别? absolute 参照最近的非 static 祖先,会随页面滚动;fixed 参照视口,滚动不动(除非父级有 transform)。
-
z-index 失效场景? 元素非定位;父元素层叠上下文限制;flex/grid 子项的层叠规则不同。
-
sticky 的兼容性限制? 父元素不能 overflow:hidden/auto/scroll;表格元素上早期 Chrome 有 bug;必须设阈值。
自测三问
position: relative; top: 20px后元素原位置还在吗?- 为什么「父相子绝」是行业惯例?
- z-index 9999 元素为什么可能被 z-index 1 的元素盖住?
小结一句话
static 排队、relative 偏移自己、absolute 相对祖先、fixed 钉在屏幕、sticky 滚到阈值粘住;z-index 在同一层叠上下文内比较。
延伸
- MDN position
- 下一课:Flex 与 Grid,现代布局的两大利器。