返回笔记列表
01 · NOTES / WebGIS 开发

第 07 节 · 定位与层叠

2026 年 9 月 1 日

第 07 节 · 定位与层叠

📌 版本信息:基于 CSS Position Module Level 3(position: sticky 已全浏览器稳定;2026-08-29 核对) 📚 来源:MDN 定位MDN z-index

一、这一节的目标

  1. 精通 position 四兄弟:relative / absolute / fixed / sticky
  2. 理解"定位参照物"——90% 的定位 bug 都在这一步
  3. 会用 z-index 管理层叠(弹窗压住地图、地图控件压住瓦片)
  4. 完成三个经典组件:固定顶栏、悬浮定位球、地图弹窗定位

二、为什么地图应用离不开定位

回想你在任何地图产品里见过的界面:右上角"图层切换"悬浮块、左下角比例尺、缩放按钮贴着地图角落、回到首页的悬浮球、随滚动钉住的顶栏——它们都不在文档流里乖乖排队,而是"浮"在地图上面。实现这些全靠 position


三、position 四兄弟

① relative:相对定位(基准选手)

.box { position: relative; top: 10px; left: 20px; }

元素还在文档流里占着原位,只是视觉上偏移一点点(偏移量相对它自己原来的位置)。单独用得少,它的主业是当 absolute 子元素的参照物(见下)。

② absolute:绝对定位(脱流飞行)

.parent { position: relative; }  /* 关键:给父亲设参照物 */
.badge {
  position: absolute;            /* 脱离文档流,不占地方 */
  top: 8px; right: 8px;          /* 相对"最近的定位祖先"定位 */
}

核心规则:absolute 元素往上层找,找到第一个 position 不是 static 的祖先作为参照物;一个都没有就相对整个页面。

这就是"子绝父相"口诀——想让孩子贴着某个容器定位,就给容器 position: relative,孩子 position: absolute

③ fixed:固定定位(钉死在视口)

.topbar { position: fixed; top: 0; left: 0; right: 0; height: 48px; }

相对浏览器视口定位,页面怎么滚动它都钉在原地。导航栏、悬浮客服按钮、"回到顶部"都是它。

④ sticky:粘性定位(滚动到临界点才钉住)

.table-head { position: sticky; top: 0; }

平时跟文档流一起滚,滚到 top: 0 的位置就"粘"住不动——表格吸顶表头、章节侧边目录的首选,比 JS 监听滚动优雅一万倍。

占文档流位置吗 相对谁定位 典型用途
relative 自己原位置 微调 + 当参照物
absolute 不占 最近定位祖先 徽标、地图角落控件
fixed 不占 视口 固定顶栏、悬浮球
sticky 占(粘住时表现如 fixed) 最近滚动祖先 表头吸顶

四、层叠上下文与 z-index

元素重叠时谁在上面?默认规则:后来的盖前面的。要主动控制,用 z-index(只在定位元素或 Flex 子项上生效):

.map-tiles { position: absolute; z-index: 1; }    /* 瓦片:最底 */
.map-controls { position: absolute; z-index: 10; } /* 控件:中间 */
.modal { position: fixed; z-index: 1000; }         /* 弹窗:最顶 */
.toast { position: fixed; z-index: 2000; }         /* 提示:压过弹窗 */

三个要点:

  1. z-index 只有同一个层叠上下文内才能比大小。父元素若创建了新的层叠上下文(如带 transformopacity < 1),子元素的 z-index 出不了这个"结界"——这就是"z-index 写了 9999 却不生效"的元凶。
  2. 不要随手写 99999。项目约定分层:普通内容 010、控件 10100、弹窗 1000、提示 2000,够用且好排查。
  3. 排查工具:DevTools → Elements → Layers 面板,能看页面分层情况。

五、经典配方(直接抄)

/* ① 固定顶栏:内容区补上等高 padding 防止被遮 */
.topbar { position: fixed; top: 0; left: 0; right: 0; height: 56px; z-index: 100; }
body { padding-top: 56px; }

/* ② 地图右上角控件组 */
.map-wrapper { position: relative; }
.map-tools { position: absolute; top: 12px; right: 12px; z-index: 10; }

/* ③ 悬浮"回到顶部"球 */
.back-top { position: fixed; right: 24px; bottom: 24px; z-index: 500; }

/* ④ 消息角标:子绝父相 */
.avatar { position: relative; }
.avatar .badge {
  position: absolute; top: -4px; right: -4px;
  min-width: 16px; height: 16px; border-radius: 8px;
  background: red; color: #fff; font-size: 12px;
}

六、动手跟练:07 · 定位与层叠

配套文件:02-web-basics/examples/07-定位与层叠.html(页面里搭了一个"假地图"+ 控件 + 弹窗 + 长内容滚动区)

步骤:

  1. Live Server 打开,读一遍现有代码(假地图就是个大 div,重点看定位)
  2. 完成 6 个 TODO:给假地图加右上角缩放控件(子绝父相)、左下角比例尺、固定顶栏(注意 body 补 padding)、消息角标、弹窗 z-index 分层、表头吸顶
  3. 故意把 .map-toolsz-index 改成 0,观察被瓦片(其实是背景)盖住的效果,再改回来

通关标准:

  • 缩放控件贴着假地图右上角(不是贴着页面右上角——参照物搞错一眼就穿帮)
  • 滚动长内容时顶栏钉在顶部、表头吸顶生效
  • 能解释弹窗为什么用 1000、角标为什么用 10

七、自测题

  1. absolute 元素找不到任何定位祖先时,相对谁定位?
  2. "子绝父相"是哪两个字的组合?为什么父亲要设 relative?
  3. fixedsticky 的本质区别?
  4. z-index 写了 9999 却被别的元素压住,最可能的原因是什么?
  5. 固定顶栏后,页面最顶部的内容被顶栏遮住一截,怎么解决?

参考答案

  1. 相对整个页面(初始包含块)。
  2. 子元素 absolute + 父元素 relative。父不设参照,子就会飞到更外层去定位。
  3. fixed 从头到尾钉死视口;sticky 平时占位随流滚动,到达临界值(top:0 等)才钉住。
  4. 祖先创建了新的层叠上下文(transform/opacity 等),把它的 z-index "封印"在父层的层级里。
  5. 给 body(或主内容区)加等高的 padding-top。

八、下一步

HTML/CSS 阶段一还差最后一块拼图 → 第 08 节:响应式与媒体查询,让同一套页面在手机、平板、桌面都好看。

TAGSweb