z-index: var(--z-modal)无效,90%是因为元素position仍为static;必须显式设为relative/absolute/fixed/sticky,且--z-modal需在顶层非scoped样式中定义,否则变量不可见或被作用域隔离。

z-index: var(--z-modal) 无效,90% 是因为没设 position
写了变量却盖不住其他元素,第一反应不该是改数值,而是打开开发者工具看「Computed」面板:如果 z-index 显示为 auto 或灰掉,说明它根本没被激活。原因只有一个——目标元素的 position 还是 static(默认值)。z-index 对 static 元素完全无效。
必须显式设置为以下之一:relative、absolute、fixed 或 sticky。常见误操作包括:
- 只给父容器设
position: relative,子元素没设定位,z-index白写 - 用
transform: translateZ(0)触发硬件加速,却忘了它会创建新层叠上下文,把子元素“关”在里面 - 第三方组件(如
uni-modal)挂载到下,但没设position,导致失去统一调度基准
:root 里定义 --z-modal ≠ 全局可用
在某个 <style scoped></style> 里写 :root { --z-modal: 1000; } 是无效的——scoped 会加属性选择器,:root 被锁死在当前组件作用域内,其他地方读不到。
真正全局生效的写法只有一处:项目顶层非 scoped 的 <style></style> 块中(如 Vue 的 App.vue、React 的 index.css),直接写:
:root {
--z-base: 0;
--z-toast: 800;
--z-dropdown: 900;
--z-modal: 1000;
--z-fullscreen: 1500;
}
UniApp 等跨端框架尤其要注意:uni.showToast 渲染的 DOM 在 下,如果变量只定义在某个 page 文件里,它完全看不到。
变量命名和数值设计要防冲突、留空档
把所有层级塞进 :root 看似省事,实则埋雷。一个 --z-modal 被多个组件共用,某天弹窗升级到 1200,侧边栏菜单就可能意外浮到最前。
更稳妥的做法是按功能域就近定义:
- 模态框内部写:
.modal { --z-element: var(--z-modal, 1000); z-index: var(--z-element); } - 下拉菜单用
--z-dropdown,Toast 用--z-toast,彼此隔离 - 数值至少留 10 点间隙:
--z-tooltip: 300、--z-modal: 900,中间预留插入空间 - 禁用
calc(var(--z-base) + 10)嵌套太深——旧版 Safari 对calc+var()支持不稳定
JS 动态读写 CSS 变量时,字符串和数值别混用
通过 JS 修改层级很常见(比如主题切换时动态降级弹窗),但 getComputedStyle().getPropertyValue('--z-modal') 返回的是字符串,直接比较会出错:
const zIndexStr = getComputedStyle(document.documentElement).getPropertyValue('--z-modal'); // "1000"
console.log(zIndexStr > 900); // true —— 字符串比较,"1000" > "900" 成立
console.log(+zIndexStr > 900); // true —— 转数字才可靠
console.log(parseInt(zIndexStr, 10) > 900); // true
真正难的不是写对变量,而是时刻意识到:z-index 永远不是孤立数字,它活在 position 和层叠上下文构成的嵌套关系里。变量只是让这个关系更可控,不是绕过它的捷径。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











