z-index必须用语义化变量统一管理并封装校验mixin;定义@z-tooltip: 300、@z-dropdown: 500等角色化变量,相邻值差≥10;强制通过.z(modal)调用,禁用裸写数字或直引变量;注意父容器触发层叠上下文(如opacity: 0.99)导致z-index局部失效。

z-index 必须用语义化变量定义,不能裸写数字
Less 里直接写 z-index: 999 看似快,但项目一上规模,dropdown 和 modal 就开始互相覆盖——不是谁数值大,而是谁先编译谁赢。真正可控的做法是把所有层级收敛到一个集中文件(如 _z-index.less),只暴露带业务含义的变量:
@z-tooltip: 300@z-dropdown: 500@z-modal-overlay: 1000@z-modal-content: 1010
相邻值至少差 10,给未来插入中间层留余地;禁用 @z-high 或 @z-max 这类模糊命名,它们在协作中等于没定义。
所有 z-index 赋值必须走 .z() mixin,禁止直引变量
光有变量还不够。开发者仍可能绕过规则,在组件里直接写 z-index: @z-modal,导致后续加个 toast 层时有人手改 @z-modal: 1001,破坏全局一致性。解决方案是封装一个带校验的 .z() mixin:
.z(@layer, @offset: 0) when (isnumber(@offset)) {
@value: ~"@@{layer}";
z-index: e(@value) + @offset;
}
调用时统一为 .z(modal) 或 .z(tooltip, +1),mixin 内部可加 warning 提示非法关键词,强制收口赋值入口。
立即学习“前端免费学习笔记(深入)”;
父容器触发新层叠上下文时,z-index 会“失效”
写了 .z(modal) 却还是被盖住?大概率不是数值小,而是某个祖先元素悄悄创建了新层叠上下文。以下任一条件都会触发:
-
opacity: 0.99(哪怕只差 0.01) -
transform: translateZ(0)或scale-95 -
filter: blur(0)或blur-sm will-change: transform
调试方法:Chrome 开发者工具切换到 «Layers» 面板,逐级点击父节点,看 «Stacking context» 是否突然变成 Yes。临时注释掉可疑属性,遮挡消失即定位成功。
导出 CSS 自定义属性时,不能只定义不使用
想让 JS 动态读取层级?别以为在 _z-index.less 里写 :root { --z-modal: 1000; } 就完事。CSS 自定义属性只是字符串容器,它不参与层叠计算——你得显式在样式规则里再用一次:
.modal { z-index: var(--z-modal); }
否则编译后输出的仍是 z-index: @z-modal(未解析)或空值。更稳妥的做法是:Less 用变量控制逻辑,最终输出必须落到具体选择器的 z-index 声明上。
最常被忽略的是层叠上下文边界和 mixin 调用路径——变量定义了、mixin 写了,但忘了 @use 或 @import,或者在嵌套作用域里重定义了同名变量,结果改了等于没改。


















