z-index失效主因是元素未定位、父容器创建层叠上下文或tailwind配置错误;需确保position非static,排查opacity

配了 z-999 还被盖住?不是数值不够大,而是它根本没参与层叠计算——90% 的问题出在元素没定位、父容器意外创建了层叠上下文,或 tailwind.config.js 里 zIndex 根本没正确定义。
为什么 z-index 类写了却完全不生效
浏览器只对非 static 定位的元素解析 z-index。哪怕你写了 z-50,只要元素的 position 是默认的 static,DevTools 的 «Computed» 面板里 z-index 就显示为 auto,等于没写。
- 常见漏操作:只加
z-50,忘了同步加relative、absolute等定位类 - React/Vue 中用 JS 动态添加 class 时,只拼
z-${depth},但没确保position同时存在 - Flex 或 Grid 子项误以为布局能力 = 定位能力,没显式设
position
快速验证:打开 Chrome DevTools → 选中元素 → «Computed» 面板搜 position,值不是 static 才算过关。
tailwind.config.js 中 zIndex 必须这样写才生成 CSS
Tailwind v3.0+ 彻底废弃数组写法,也拒绝 extend.zIndex。错一个字符,z-modal 这类 class 就不会出现在最终 CSS 里。
-
zIndex必须完整定义在theme.zIndex下,不能只写extend: { zIndex: { 'modal': '60' } } - 键名必须加引号:
'modal'✅,modal❌(JS 会尝试解析为变量,可能截断) - 值必须是字符串:
'60'✅,60❌(虽偶有侥幸,但 JIT 模式不保证兼容性) - 改完必须重启开发服务器——Tailwind 不热重载配置变更
正确示例:
module.exports = {
theme: {
zIndex: {
'background': '0',
'dropdown': '30',
'tooltip': '40',
'modal-overlay': '60',
'modal-content': '70',
}
}
}
父容器悄悄创建了层叠上下文,子元素 z 值再大也没用
只要某个祖先元素满足以下任一条件,它就创建独立层叠上下文,把所有后代“锁”在里面比大小:
-
opacity小于 1(哪怕opacity: 0.999) -
transform不为none(包括translateZ(0)、scale(1)) -
filter、will-change、backdrop-filter不为none - 本身是
fixed或sticky且z-index非auto
两个兄弟弹窗各自父容器都触发了新上下文 → 它们的堆叠顺序由 HTML 顺序决定,跟子元素 z- 值无关。调试时打开 Chrome «Layers» 面板,或逐级点击父节点看 «Layout» 标签页是否出现「Stacking context: Yes」。
别用 z-[999] 动态拼接,除非你已控制 content 扫描范围
z-[999] 看似灵活,实际是维护黑洞:
- React 中写
class={`z-[${depth}]`},JIT 模式根本不会扫描运行时字符串,构建后 CSS 里没有这条规则 - 没人知道
z-[999]对应什么 UI 角色,下次加个Tooltip该用 998 还是 1001?冲突后无法溯源 - 第三方组件(如 Headless UI)内联
z-10,而你的z-[999]因注入顺序靠前反被覆盖
真正可控的做法:提前在 theme.zIndex 中定义语义化层级(如 'tooltip'、'modal-overlay'),然后在模板里写 z-tooltip —— 可读、可查、可复用。
最常被忽略的一点:z-index 不是全局排序器,它只在一个层叠上下文中起作用;而那个上下文,往往不是你眼睛看到的“父容器”,而是某个透明度为 0.99 的 div、某段无害的 transform: scale(1),甚至是你自己写的 z-0 —— 因为 z-index: 0 也会创建新上下文。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











