z-index生效需同时满足两个硬条件:元素position必须为relative/absolute/fixed/sticky,且不能处于父级意外创建的层叠上下文中(如父元素含transform、opacity<1等)。

直接在 HTML 里写 z-999 或 z-[999] 很难精准控制——真正起作用的不是数字大小,而是层叠上下文是否对齐、配置是否生效、定位是否到位。
为什么 z-50 写了却没效果?先查两个硬条件
z-index 类名本身只是把 CSS 的 z-index 值塞进去,它完全不保证“生效”。必须同时满足:
- 元素自身
position必须是非static值(relative、absolute、fixed、sticky) - 该元素不能处于一个被父级意外创建的层叠上下文中(比如父元素有
transform、opacity: 0.99、filter、will-change)
常见失效场景:
- 给按钮加
z-50却忘了设relative→ 完全无效 - 模态框嵌在
transform: scale(0.99)的容器里 → 子元素的z-70只在该缩放上下文内有效 - 两个兄弟弹窗各自父容器都触发了新层叠上下文 → 它们的堆叠顺序由 HTML 顺序决定,跟子元素的
z-值无关
如何在 tailwind.config.js 中正确定义自定义 z-index
Tailwind v3.0+ 已废弃数组写法和 extend.zIndex 追加式配置。必须把完整映射写在 theme.zIndex 下,且键名必须是字符串。
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确:
zIndex: { 'modal-overlay': '60', 'tooltip': '40', 'toast': '50' } - ❌ 错误:
extend: { zIndex: { 'modal-overlay': '60' } }→ 不生成任何类 - ❌ 错误:
zIndex: ['0', '10', '60']→ 数组写法已废弃 - ❌ 错误:
zIndex: { modal-overlay: '60' }→ JS 解析为modal键,-overlay被截断
改完必须重启 dev server —— Tailwind 不热重载配置变更。
z-[999] 和动态 class={`z-[${depth}]`} 为什么不可靠?
z-[999] 是 JIT 模式下的任意值语法,依赖 content 字段中**静态出现**该字符串。React 中写 class={`z-[${depth}]`} 构建时根本不会识别,生产环境必漏生成。
- 构建工具无法解析模板字符串中的变量,
depth是运行时值,不是字面量 - 即使扫描到
z-[999],它也不会自动推导出z-[998]或z-[1000] - 语义缺失:没人知道
z-[999]对应什么 UI 角色,下次加个 Tooltip,该用 998 还是 1001?冲突后无法溯源
更稳的做法:提前在 theme.zIndex 中定义带语义的键,组件内统一用 z-tooltip,而非 z-40 或 z-[40]。
嵌套浮层(如 modal 里有 tooltip)怎么避免层级错乱?
不是数值不够大,而是上下文被切割了。当 modal 自身已创建新层叠上下文(比如用了 transform 或 backdrop-blur),它的子元素 z-tooltip 就只在这个 modal 上下文内比大小。
- 如果 modal content 是
z-70,tooltip 至少得设为z-80,否则会被盖住 - 但更关键的是检查 modal 容器是否无意中触发了新上下文(比如加了
opacity: 0.99) - 移动端键盘弹出时,某些安卓 WebView 会重置根层叠上下文 → 浮层可能突然失效,这时可强制给
<body>加style="z-index: 0"来稳定根上下文
真正卡住人的从来不是 z- 值写多少,而是没意识到:每个 position: relative/absolute/fixed 元素是否处在同一层叠上下文里。检查父级有没有无意中触发新上下文,比反复调大 z- 数字管用得多。


















