B03 定位与层叠上下文
B03 定位与层叠上下文
摘要:
position决定元素相对谁定位,z-index决定它在谁之上。两者不是独立生效的:z-index只在同一层叠上下文内比较,而某些属性(transform、opacity、filter)会就地创建新的上下文,导致再大的z-index也无法越过。本文用一个可复现的例子说明这条规则。
关键词:定位,绝对定位,吸顶,z-index,层叠上下文
所属:frontend/css / B-进阶 | 上一篇:B02-单位与数学函数 | 下一篇:B04-伪类与伪元素
1 引言
弹层被导航遮住、吸顶栏在滚动时抖一下、z-index: 9999 仍然无效,这三类问题的根因都是层叠上下文。
本文给出定位取值、z-index 的比较规则与创建上下文的条件。范围见表 1-1。
| 项 | 本文覆盖 | 本文不覆盖 |
|---|---|---|
| 定位 | static、relative、absolute、fixed、sticky |
锚点定位与滚动驱动动画 |
| 层叠 | z-index 与上下文创建条件 |
3D 变换矩阵 |
| 场景 | 弹层、吸顶栏、遮罩 | 复杂组件层级体系 |
2 预备知识
| 项 | 要求 | 核对方式 |
|---|---|---|
| 环境 | 本地服务器可用 | 浏览器能打开 localhost |
| 文件 | css-practice/stack.html |
编码 UTF-8 |
| 浏览器 | Chrome 130+,Layers 面板可用 | 能看到层叠结构 |
| 前置 | A05 | 理解脱离流 |
3 原理与实现
3.1 先比上下文,再比 z-index
z-index 的比较只在同一上下文内有效,如图 3-1 所示。
flowchart TD
R["根层叠上下文"] --> A["元素 A<br/>z-index: 1"]
R --> B["元素 B<br/>transform: translateZ(0)<br/>创建新上下文"]
B --> C["子元素 C<br/>z-index: 9999"]
A -->|"与 B 比较"| B
C -->|"只在 B 内部比较"| C
图 3-1 上下文内的 z-index 比较
图上可见:C 的 9999 只在 B 内部有效,整体仍低于 A;要提升 C,需要提升 B。
3.2 三种常用定位写法
/* 运行环境:Chrome 130+;css-practice/stack.css */
.site-header {
position: sticky;
inset-block-start: 0;
z-index: 10;
background: #ffffff;
}
.hero { position: relative; }
.hero__badge {
position: absolute;
inset-block-start: 0.75rem;
inset-inline-end: 0.75rem;
background: #1d4ed8;
color: #fff;
padding: 0.25rem 0.5rem;
border-radius: 999px;
}
.backdrop {
position: fixed;
inset: 0;
background: rgb(15 23 42 / 0.4);
z-index: 100;
}
.modal {
position: fixed;
inset-block-start: 50%;
inset-inline-start: 50%;
translate: -50% -50%;
z-index: 101;
background: #fff;
padding: 1.5rem;
border-radius: 0.75rem;
}
定位取值与参照物见表 3-1。
| 取值 | 是否脱离流 | 参照物 | 典型场景 |
|---|---|---|---|
static |
否 | — | 默认 |
relative |
否 | 自身原位置 | 作为子元素定位基准 |
absolute |
是 | 最近的定位祖先 | 角标、下拉菜单 |
fixed |
是 | 视口 | 弹层、遮罩 |
sticky |
否 | 滚动容器 + 偏移阈值 | 吸顶导航、表头 |
创建新层叠上下文的条件见表 3-2。
| 条件 | 示例 | 影响 |
|---|---|---|
定位 + z-index 非 auto |
position: relative; z-index: 1 |
形成独立层级 |
transform 非 none |
transform: translateZ(0) |
常用于动画,副作用是建上下文 |
opacity 小于 1 |
opacity: 0.9 |
动效常见副作用 |
filter 非 none |
filter: blur(2px) |
同上 |
isolation: isolate |
显式隔离 | 推荐用于需要独立层级的组件 |
4 验证与讨论
- 滚动页面,确认吸顶导航留在顶部,且不遮挡弹层。
- 打开弹层,确认遮罩覆盖整页,弹层位于遮罩之上。
- 给弹层外的祖先加
transform: translateY(0),观察弹层被压到导航下方,复现上下文问题。 - 用 Layers 面板查看各元素所属层,确认与预期一致。
| 检查项 | 预期结果 | 说明 |
|---|---|---|
| 吸顶 | 滚动时导航固定在顶部 | sticky + 偏移 |
| 弹层层级 | 遮罩 < 弹层 < 无其它层级冲突 | 同上下文内比较 |
| 上下文陷阱 | 祖先加 transform 后层级变化 | 表 3-2 |
| 定位基准 | 角标相对 .hero 定位 |
父级 relative |
讨论与局限。 sticky 在祖先有 overflow: hidden 时失效,这是吸顶不生效的首要原因。另 z-index 的数值应分层管理(如 10 / 100 / 1000),随意取大值会让后续维护无法判断顺序。
5 常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| z-index 无效 | 祖先创建了上下文 | 提升祖先层级,或移除 transform |
| 吸顶不生效 | 祖先有 overflow: hidden |
移除该属性,或改用 fixed |
| 绝对定位跑到页面左上角 | 父级没有 position |
父级加 relative |
| 弹层随页面滚动 | 使用 absolute 而非 fixed |
改 fixed 或挂到 body |
| 遮罩下方仍可点击 | 遮罩只覆盖视觉,未覆盖点击区域 | 确保 inset: 0 且层级正确 |
6 结论
| 序号 | 结论 | 依据 |
|---|---|---|
| 1 | 先比上下文,再比 z-index | 图 3-1 |
| 2 | transform、opacity、filter 会创建上下文 | 表 3-2 |
| 3 | 吸顶失败先查祖先 overflow | 5 节常见问题 |
| 4 | z-index 分层取值,不随性取大数 | 讨论 |
- 上一篇:B02-单位与数学函数
- 下一篇:B04-伪类与伪元素
- 返回:B00-总结 | 科目 README
参考文献
[1] MDN Web Docs · position 属性,https://developer.mozilla.org/zh-CN/docs/Web/CSS/position(访问于 2026-10-31)
[2] MDN Web Docs · 层叠上下文,https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_positioned_layout/Stacking_context(访问于 2026-10-31)

评论 0
还没有评论,快来抢沙发吧~