B03 定位与层叠上下文

2026-10-31 17:170 阅读约 10 分钟CSS

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 验证与讨论

  1. 滚动页面,确认吸顶导航留在顶部,且不遮挡弹层。
  2. 打开弹层,确认遮罩覆盖整页,弹层位于遮罩之上。
  3. 给弹层外的祖先加 transform: translateY(0),观察弹层被压到导航下方,复现上下文问题。
  4. 用 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 分层取值,不随性取大数 讨论

参考文献

[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

0/2000

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