← 首页 / CSS stacking context · 拆解 待审核
z-index · stacking order

CSS stacking context · 拆解

为什么 z-index: 9999 有时压不住别的元素?把页面看成一摞文件夹,逐节厘清 stacking context 的排序法则触发条件isolation: isolate 的用途,以及三个最常见的排错场景。每节都可以拖滑块 / 切换开关,实时观察真实浏览器的 stacking order。

阅读前默认你已了解 z-indexposition 的基本含义:同一个 stacking context 内,z-index 大的元素叠在上面、相同时按文档顺序。本系列要解决的是另一层问题——跨 stacking context 时,z-index 的比较为何不再成立。

取材自 Smashing Magazine《Unstacking CSS Stacking Contexts》(2026-01),并补足 MDN 触发清单。四节:排序法则谁会创建 stacking contextisolation: isolate三个常见排错场景

1 · 排序法则:先排文件夹,再排文件夹里的纸

把页面想成一张桌子,每个元素是一张纸,后写的盖在先写的上面。stacking context 相当于一个文件夹:一张纸一旦被放进某个文件夹,它就只在该文件夹内部参与排序,既不会跑到文件夹外,也不会插到别的文件夹的纸中间。

因此浏览器决定元素叠放顺序时,遵循一条核心法则——先按 stacking order 把文件夹整体排序,再排每个文件夹内部的纸。子元素的 z-index 只在自己所属的 stacking context 内有意义,不会拿去和别的 stacking context 里的元素直接比较。

1.1 · 动手:两个文件夹,各装一张纸

下面两个面板各自是一个 stacking context(position:relative + z-index),各装一个会探出边界、互相重叠的子徽标。把红子徽标的 z-index 拉到 9999,观察它能否压过蓝子徽标。

读法:纸 A 无论 z-index 多大,只要它所在的文件夹 A 整体排在文件夹 B 下面(stacking order 更低),纸 A 就始终在纸 B 下面。z-index: 9999 在跨 stacking context 比较里不参与计算

1.2 · 那"根"在哪?

最外层的根 stacking context 由 <html> 元素构成。只要一个元素没有创建新的 stacking context,它的子孙就直接参与最近祖先 stacking context 的排序——这也是为什么没设 z-index 时,页面看起来扁平、按文档顺序叠放。至于哪些属性会创建一个新的 stacking context,见 谁会创建 stacking context

2 · 谁会创建 stacking context

本节延续 排序法则:子元素的 z-index 只在所属 stacking context 内有效。能创建新 stacking context 的属性相当多,因此常常会无意间创建出一个、把子元素限制在内部。下面用一个跨层级测试把这些属性逐一辨认出来。

跨层级测试怎么读:舞台里有一条 z-index: 1 的红条。蓝色测试盒本身没设 z-index(auto),里面塞了个 z-index: 999 的子徽标。

  • 若测试盒没有创建 stacking context → 子徽标直接参与根 stacking context,凭 999 压在红条之上
  • 若测试盒创建了 stacking context → 子徽标被限制在盒内,整盒按 auto 排序,于是沉到红条之下。逐个开启属性,观察徽标在哪个属性下沉到红条之下。

2.1 · 完整清单(MDN 口径)

下面任意一条成立,该元素就会创建一个新的 stacking context:

  • 根元素 <html>
  • position: absolute/relativez-indexauto
  • position: fixedsticky(自身即创建,无需 z-index)
  • opacity < 1
  • transform / scale / rotate / translatenone
  • filter / backdrop-filternone
  • perspective / clip-path / mask / mask-imagenone
  • mix-blend-modenormal
  • isolation: isolate
  • contain: layout / paint / strict / content
  • will-change 指定了任何"会创建上下文"的属性(如 transformopacity
  • flex / grid 容器的子项且 z-indexauto

完整、权威的触发条件清单与示例见 MDN · Stacking context

注意其中的"假阳性"条件:overflow: hiddenposition: relative(不带 z-index)不会创建 stacking context——上面把它们也放进了开关里,可以看到徽标依旧浮在红条之上。但 overflow: hidden 会带来另一类问题(裁切),见 三个常见排错场景

3 · isolation: isolate——无副作用地创建 stacking context

本节延续 谁会创建 stacking context 列出的触发条件。其中大多数属性都附带改变视觉:opacity 会变透明、transform 会改变位置、filter 会改变像素。只有 isolation: isolate专门用于创建一个 stacking context、且不产生其他视觉效果的属性。

3.1 · 典型场景:装饰用的 ::before { z-index: -1 } 消失了

卡片想用伪元素 ::before 作背景装饰(渐变),让它压在文字下面、卡片背景上面,于是给它 z-index: -1。结果装饰消失了——因为卡片本身不是 stacking context 时,这个 -1 会落到整张卡片(连同它的白底)的下面,被白底遮住。

给卡片加一行 isolation: isolate,卡片就成为独立的 stacking context,-1 被限制在卡片内部——此时它在卡片白底之上、文字之下,装饰正常显现。

为什么优先选 isolate:同样能"把 z-index: -1 限制在卡片内部"的做法还有给卡片设 transformopacity: .999,但它们都带副作用(可能触发合成层、改变模糊/抗锯齿、影响 position:fixed 子元素的 containing block)。isolation: isolate 表达的意图最明确:仅创建一个新的 stacking context,不做其他。

3.2 · 另一个常见用途:为组件划定边界

在设计系统里给可复用组件的根节点加 isolation: isolate,可以保证组件内部任意大的 z-index 都不会泄漏出去、压到组件外的元素;反过来外部的 z-index 也无法插入组件内部。整个组件成为一个 stacking order 可预测的独立 stacking context。

4 · 三个常见排错场景

本节用到的"困在祖先的 stacking context 里"概念,见 排序法则谁会创建 stacking context。几乎所有"z-index 拉到 9999 仍压不住"的问题,根因都相同:目标元素被限制在某个祖先的 stacking context 内部。下面三个是最常见的形态,每个都带修复开关。

4.1 · 其一:被困的 Modal

Modal 设了 z-index: 9999,却被正文(z-index: 2)盖住——因为它是 z-index: 1 的 header 的子元素,被 header 这个 stacking context 限制在内部。修法:把 Modal 移到 header 外(Portal)。

4.2 · 其二:沉底的 Dropdown

导航栏里的下拉菜单 z-index: 100,被下方正文 z-index: 2 盖住——因为下拉被限制在 navbar(z-index: 1)内部,跨 stacking context 比较时只看 1 vs 2。修法:把 navbar 的 z-index 提到正文之上。

4.3 · 其三:被裁切的 Tooltip(z-index 无法解决)

Tooltip 设了 z-index: 1000,却被切掉一截——原因不是 stacking order,而是祖先的 overflow: hidden裁切与 z-index 无关:再大的 z-index 也无法恢复被裁掉的像素。修法:去掉裁切,或把 tooltip 移出溢出容器。

4.4 · 排错三步法

  1. 沿 DOM 向上逐层检查祖先,看是否有 谁会创建 stacking context 列出的那些创建 stacking context 的属性。
  2. 找到把目标限制在内部的那个祖先后,三选一:提高该祖先的 z-index / 重排 HTML 把目标移出去 / 用框架的 Portal 渲染到 <body> 下。
  3. 怀疑是裁切(而非 stacking order 问题)时,检查祖先的 overflowclip-path

可用工具:Chrome 扩展 "CSS Stacking Context Inspector"、VS Code 扩展 "Better CSS Stacking Contexts",以及 Edge / Firefox DevTools 的 3D / Layers 视图,都能直接标出页面上的 stacking context。

规范 / 文档