CSS position 速查:relative/absolute/fixed/sticky 怎么用(含 8 个常见场景)

用最短路径讲清 CSS position 的四种定位方式(relative/absolute/fixed/sticky)与核心概念(定位参照、脱离文档流、z-index)。附 8 个常见布局示例与 sticky 失效避坑清单。

54 分钟阅读
CSS
CSS position 速查:relative/absolute/fixed/sticky 怎么用(含 8 个常见场景)

position 是 CSS 布局里最容易“看起来懂了但一用就错”的属性:

  • absolute 到底相对谁?
  • sticky 为什么不生效?
  • z-index 为什么没用?

这篇文章用最短路径讲清:4 种定位方式怎么选、背后的核心概念是什么,并给你 8 个最常见的实战场景代码。

如果你的目标是“做网页并上线”,最后还会给你一组把 CSS 技术导向“可视化编辑/模板/上线发布”的入口。


核心概念 1:文档流(Normal Flow)与“脱离文档流”

默认情况下,元素在普通文档流中排列:块级从上到下,行内从左到右。

当元素使用 position: absolute(或 fixed)后,通常会脱离文档流

  • 它不再占据原本的空间
  • 后续元素会“顶上来”

这就是很多“布局突然塌了/重叠了”的根源。


核心概念 2:定位参照(Containing Block)

absolute 的定位不是“相对屏幕”,而是相对它的定位参照(更准确说:包含块)。

实践中你可以用一个经验法则记住:

position: absolute 会优先相对“最近的、非 static 的祖先元素”定位(也就是祖先里最近的 position: relative/absolute/fixed/sticky)。

如果一路往上都找不到,那就会回到页面根(视口/初始包含块)附近,效果就像“相对整个页面”。


4 种定位方式:什么时候用哪个?

1)position: static(默认)

  • 不定位
  • top/right/bottom/left 无效

绝大多数元素都是 static

2)position: relative(相对定位)

  • 元素仍然占据原来的空间
  • 你可以用 top/left 让它相对原位置偏移
  • 关键用途:为子元素的 absolute 提供定位参照
.card {
  position: relative; /* 给角标一个参照 */
}

.card__badge {
  position: absolute;
  top: 12px;
  right: 12px;
}

绝大多数“角标/右上角按钮/覆盖层”的正确打开方式:父容器 relative,子元素 absolute

3)position: absolute(绝对定位)

  • 通常脱离文档流
  • 通过 top/right/bottom/left 相对“包含块”定位
  • 适合:角标、覆盖层、弹出层内部定位、图标叠加
.avatar {
  position: relative;
  width: 64px;
  height: 64px;
}

.avatar img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

.avatar::after {
  content: "";
  position: absolute;
  right: 2px;
  bottom: 2px;
  width: 12px;
  height: 12px;
  background: #22c55e;
  border: 2px solid #fff;
  border-radius: 9999px;
}

4)position: fixed(固定定位)

  • 相对视口(viewport)定位
  • 不随页面滚动而移动
  • 适合:悬浮按钮、固定导航、回到顶部
.fab {
  position: fixed;
  right: 20px;
  bottom: 20px;
  width: 48px;
  height: 48px;
  border-radius: 9999px;
}

注意:移动端上 fixed 可能受浏览器地址栏、软键盘影响出现“跳动”,需要实际设备测试。

5)position: sticky(粘性定位)

  • “相对定位 + 滚动吸附”的组合
  • 在达到阈值前像 relative,达到阈值后像 fixed
  • 适合:目录吸顶、表头吸顶、侧栏跟随
.toc {
  position: sticky;
  top: 12px;
}

sticky 的关键是:它是在某个滚动容器内粘住,而不是全局。


sticky 为什么不生效?一张避坑清单

sticky 失效的原因几乎都集中在下面几条:

  1. 没有设置阈值:必须有 top(或 bottom
  2. 父级高度不够:父容器没有可滚动的空间
  3. 祖先元素设置了 overflow: hidden/auto/scroll:sticky 会在最近的滚动容器内生效,或者被裁切
  4. 用了 transform/filter/perspective:某些情况下会创建新的包含块/层叠上下文,导致表现异常
  5. 表格/特殊布局table 相关元素 sticky 兼容性与细节更复杂

排查顺序建议:先看是否有 top,再检查父容器高度与 overflow。


z-index 为什么没用?先理解“层叠上下文”

很多人以为 z-index: 9999 就能“盖住一切”,但实际上 z-index 只在同一个层叠上下文里比较。

常见创建层叠上下文的方式包括:

  • position 非 static 且设置了 z-index
  • transform 不为 none
  • opacity < 1
  • filterperspective

如果你遇到弹层被遮住:

  • 先确认弹层所在的容器是否被某个祖先建立了“局部世界”
  • 再考虑把弹层挂到更高层(例如页面根部)

(如果你想系统理解覆盖关系,也可以参考站内 CSS 特异性与层叠相关内容:/css/the-battle-of-css-specificity-cascade-levels-vs-bem-vs-utility-classes


8 个最常见场景(复制即用)

场景 1:卡片右上角角标(推荐写法)

.card {
  position: relative;
}

.badge {
  position: absolute;
  top: 12px;
  right: 12px;
  padding: 4px 8px;
  border-radius: 9999px;
  background: #111827;
  color: #fff;
  font-size: 12px;
}

场景 2:图标叠加(播放按钮覆盖在封面图上)

.cover {
  position: relative;
}

.cover__play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

场景 3:吸顶导航(sticky)

.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(10px);
}

场景 4:目录侧栏吸附(sticky + 合理高度)

.layout {
  display: grid;
  grid-template-columns: 1fr 280px;
  gap: 24px;
}

.aside {
  position: sticky;
  top: 16px;
  align-self: start;
}

场景 5:回到顶部按钮(fixed)

.back-to-top {
  position: fixed;
  right: 16px;
  bottom: 16px;
}

场景 6:全屏遮罩(overlay)

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}

场景 7:弹窗居中(fixed + translate)

.modal {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(560px, calc(100vw - 32px));
  background: #fff;
  border-radius: 12px;
}

场景 8:tooltip(提示气泡)

.tooltip {
  position: relative;
}

.tooltip__content {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%);
  white-space: nowrap;
}

什么时候别用 position:优先 flex/grid

很多“布局”问题,用 position 只是绕路。

  • 两端对齐:优先 display: flex; justify-content: space-between;
  • 网格列表:优先 display: grid
  • 垂直居中:优先 flexgrid 的对齐属性

position 更适合做“叠加/吸附/覆盖”这种偏特效的事情。


常见问题(FAQ)

absolute 相对谁?

相对最近的“非 static 祖先”定位;如果没有,就会更接近相对视口/页面根。

relative 会不会影响布局?

relative 不会让元素脱离文档流,仍占据原空间;它更多用于“偏移”或作为 absolute 的参照。

sticky 为什么不生效?

优先检查:是否设置了 top;祖先是否有 overflow;父容器是否有足够高度与滚动空间。

z-index 为什么没用?

因为 z-index 只在同一个层叠上下文里比较。检查祖先是否因为 transform/opacity/z-index 创建了新的层叠上下文。

fixed 在手机端为什么会跳?

可能与地址栏伸缩、软键盘、浏览器实现有关。需要真机测试,必要时调整策略(例如减少 fixed 元素数量)。


下一步:把 CSS 技术用到“能上线”的页面里

如果你是为了“做网页并发布”,建议把这类 CSS 技术用到模板与落地页中:

  • 响应式断点怎么定(从内容出发):/css/css-responsive-breakpoints-strategy
  • Flex 和 Grid 的场景选择:/css/flex-vs-grid-layout-scenarios-guide
  • 在线网页制作平台选型:/about-html/online-website-builder-platform
  • 可视化编辑器上手:/about-html/visual-html-editor-guide
  • 模板三条路径对比:/about-html/html-templates-comparison
  • 直接开始制作:/builder

下一步:不用记这么多 CSS,直接做出网页

学完 position 还是觉得有点晕,或者只是想从 0 到 1 快速上线一个页面?

你可以试试这些工具,它们帮你把 CSS 规则可视化: