z-index 必须用命名变量而非裸数字,需预留层级间隙、主动创建可控层叠上下文,并同步CSS变量与JS动态提层。

z-index 必须用命名变量,不能写裸数字
手写 z-index: 9999 是高危操作,不是“不够优雅”,而是线上事故的直接诱因。它导致三类硬伤:数值无语义(1200 是遮罩还是下拉菜单?)、易冲突(两个模块都写 1000,但因父级 stacking context 不同,一个被压底)、难维护(加新组件时得全局 grep 找“下一个空闲值”,漏一处就错一片)。必须用 Sass 或 CSS 变量显式命名,比如 $z-modal-overlay、--z-dropdown——IDE 能跳转,拼错会编译报错或运行时报错,而不是静默失效。
数值要严格递增且留间隙
层级不是按需分配,而是预留空间的结构设计。常见错误是紧挨着设 $z-toast: 800、$z-modal: 801,结果新加个 tooltip 就卡在中间没法插。正确做法是人为留出余量:
$z-tooltip: 300$z-dropdown: 700$z-modal-overlay: 1000$z-modal-content: 1010
每档至少空 99~100 点,方便后续插入中间层级(如 $z-combo-box: 950),也避免和第三方库(Ant Design 默认 1000)撞车。
必须主动创建可控的层叠上下文
很多 z-index 失效,根本原因不是值小,而是元素没进对的层叠上下文。不要依赖 transform 或 opacity 触发——它们副作用多(模糊、滚动异常)。最稳妥的方式是给容器显式设:
立即学习“前端免费学习笔记(深入)”;
-
position: relative+z-index: 0(或任意非auto值) - 确保所有需要参与统一调度的组件,其最近的层叠上下文根节点是同一个(比如都挂载在
body下,且body有position: relative) - 第三方弹窗(如
uni.showToast)若渲染到body,而body没定位,它的z-index就完全脱离你的管理体系
CSS 变量和 JS 动态提层必须同步
Sass 变量编译后就没了,JS 拿不到;CSS 自定义属性可读可写,但必须导出正确、作用域清晰:
- 全局变量只在顶层非
scoped样式中定义::root { --z-modal: 1000; },不能写在<style scoped>里 - JS 修改时用
el.style.setProperty('--z-modal', '1050'),别传字符串'1050px'或漏掉双短横 - 禁止混用:
z-index: $z-modal和z-index: var(--z-modal)同时存在,会导致维护断层
真正容易被忽略的是:同一功能域的变量应就近定义(比如 .dropdown 内部设 --z-drop),而不是全塞进 :root——否则一个组件升级 z 值,可能意外顶起另一个毫不相关的浮层。


















