z-index管理不能依赖SCSS列表排序,因其无法应对运行时层叠上下文;正确做法是用SCSS定义语义化初始值并导出为CSS变量,由JS动态调整,同时确保position属性和锚点条件满足。

z-index 管理不是靠 SCSS 列表“排个序”就能解决的——它根本管不了运行时层叠上下文,硬用 $z-index-list 或 index() 函数只会让问题更隐蔽。
为什么 index($list, $item) 不是层级管理方案
它输出的是固定数字,编译完就冻结了,对以下情况完全无感:
-
transform或opacity: 0.99在父容器上触发新 stacking context,子元素再大的z-index也出不去 -
createPortal把Dropdown挂到body,但body没设position: relative,导致它的z-index和页面所有 fixed 元素平级比大小 - 多个 Modal 依次打开,后开的需要动态高于前一个,而列表里写死的
1000无法自增
你看到的“排序”,只是在模拟一个静态表格,不是在控制浏览器实际绘制顺序。
正确做法:SCSS 只负责定义语义化初始值,导出为 CSS 自定义属性
把 SCSS 当作“配置源”,而非“运行时控制器”:
立即学习“前端免费学习笔记(深入)”;
- 在
_z-index.scss中用map定义命名空间:$z-index: (modal: 1000, toast: 800, dropdown: 750); - 用
:root批量导出为 CSS 变量::root { --z-modal: #{map-get($z-index, modal)}; --z-toast: #{map-get($z-index, toast)}; } - 组件内直接使用:
z-index: var(--z-modal);,不调map-get() - JS 需要提层时,改写变量:
el.style.setProperty('--z-dropdown', '1050');
这样既保留 SCSS 的集中维护优势,又把决策权交给运行时。
容易被忽略的 DOM 和 CSS 锚点
z-index 生效的前提不是“数值够大”,而是三层锚点都守住:
- 目标元素必须有
position: relative(或absolute/fixed),static下设z-index完全无效 - 它的最近定位祖先不能意外创建 stacking context:检查是否带
transform、opacity < 1、filter或will-change - Portal 类组件挂载点(如
body)需显式设position: relative且z-index: 0,否则其子元素的z-index是和整个页面其他定位元素裸拼大小
复杂点从来不在怎么排数字,而在于 stacking context 是嵌套的、隐式的、由多个 CSS 属性共同触发的——你没法靠一张 SCSS 列表穷举所有组合。


















