直接写死 z-index 会因模块间数值冲突导致层叠错乱;应使用 CSS 自定义属性定义语义化、留有间隔的层级变量(如 --z-modal: 500),配合定位上下文使用,并统一管理断点变量(如 --breakpoint-md: 768px)以提升可维护性与响应式一致性。

为什么直接写死 z-index 值会出问题
项目中期开始频繁出现「明明设了 z-index: 999,还是被遮住」的情况,根本原因是:不同模块各自维护一套数字体系,比如弹窗用 999、导航栏用 1000、加载蒙层又用 9999,最后谁大谁小全靠猜,还容易因重构漏掉某处导致层叠错乱。
用 CSS 自定义属性定义层级阶梯
把 z-index 当成一套有语义的「楼层编号」来管理,而不是无意义的整数堆砌。关键不是值多大,而是层级之间有明确的相对关系和预留空间。
- 在
:root中定义基础层级变量,例如::root { --z-nav: 100; --z-dropdown: 200; --z-modal: 500; --z-toast: 800; --z-overlay: 900; } - 每个值之间留足间隔(如 100),方便后续插入中间层级(比如新增一个
--z-dropdown-submenu: 250) - 组件内直接使用:
z-index: var(--z-modal);,不拼接、不计算、不硬编码 - 避免在变量里写表达式(如
calc(var(--z-modal) + 1)),CSS 运行时无法保证所有浏览器解析顺序一致,尤其在嵌套堆叠上下文中极易失效
断点也该是语义化变量,不是像素值集合
把 @media (min-width: 768px) 这类写法散落在各处,会导致响应式逻辑碎片化。一旦设计稿调整为 769px 触发,你得全局搜索替换,还可能漏掉某处 767px 的反向判断。
- 统一定义断点变量:
:root { --breakpoint-sm: 576px; --breakpoint-md: 768px; --breakpoint-lg: 992px; --breakpoint-xl: 1200px; } - 媒体查询中直接引用:
@media (min-width: var(--breakpoint-md)) { ... } - 注意:Sass/Less 等预处理器的变量不能替代这个,因为它们在构建时就展开了,无法被 JS 动态读取或 runtime 覆盖;而原生 CSS 变量可被 JS 修改,适合做主题切换或运行时适配
- 不要用
%或em定义断点值——媒体查询只接受绝对长度单位(px、rem等),var(--breakpoint-md)必须是有效长度
z-index 和断点变量必须配合定位上下文使用
自定义属性本身不解决层叠逻辑,它只是让数值更可控。真正决定元素是否能被 z-index 影响的,是它是否创建了新的堆叠上下文。
立即学习“前端免费学习笔记(深入)”;
- 哪怕用了
z-index: var(--z-modal),如果父容器是position: static且没设z-index,子元素依然按文档流堆叠 - 常见陷阱:给
position: relative的容器设了z-index: 1,结果里面绝对定位的子元素怎么调z-index都不生效——因为该容器已创建新堆叠上下文,子元素的z-index只在这个上下文内有效 - 断点变量在媒体查询中生效的前提是:该查询规则最终生成的样式被实际应用。如果被更高优先级规则覆盖(比如 inline style 或
!important),变量再规范也没用


















