z-index必须配合层叠上下文才生效,BEM块应自主创建上下文(如position+ z-index),避免隐式触发,并通过语义化变量统一管理层级。

为什么不能直接在 BEM 块里写 z-index: 9999
因为 z-index 不是孤立属性,它只在「层叠上下文(stacking context)」内生效。一个 .modal 块即使写了 z-index: 9999,如果它的父容器(比如 .page)没创建层叠上下文,那这个值根本不会触发新层级;反过来,如果父容器用了 transform 或 opacity: 0.99,它自己就创建了上下文,子块的 z-index 就只能在这个小世界里比大小——和页面其他模块完全无关。
z-index 必须配合层叠上下文创建才有效
在 BEM 中,每个块应自主决定是否创建层叠上下文,而不是依赖外部环境。常见做法是:
- 对需要“浮出”的块(如
.modal、.tooltip、.dropdown),显式添加position: relative或position: fixed并配z-index - 避免用
opacity、filter、will-change等隐式创建上下文的属性干扰块的层级意图 - 不把
z-index放进通用工具类(如u-z-top),否则无法控制上下文边界
例如:
.modal {
position: fixed;
z-index: 1000; /* 明确创建上下文 */
}
<p>.tooltip {
position: absolute;
z-index: 1010; /<em> 高于 modal,但仅在其父上下文中生效 </em>/
}
如何避免跨块 z-index 冲突
BEM 的块是独立单元,但视觉上常需明确层级关系(比如弹窗要盖住下拉菜单)。这时不能靠猜数字,而要建立可维护的层级契约:
- 定义一组语义化层级常量,如
$z-modal: 1000、$z-dropdown: 100、$z-tooltip: 200,统一放在_zindex.scss中 - 每个块只使用这些变量,不硬编码数字;修改一处,全站响应
- 禁止块内用
z-index: inherit或z-index: unset—— 这等于放弃控制权 - 若某块需临时提升(如全屏编辑模式),用修饰符:
.editor--fullscreen .editor__canvas单独设z-index,不污染基础值
树形控件中节点展开时的 z-index 怎么办
像 .tree-node 这种递归块,每个实例都可能动态创建子菜单或浮层。此时不能给每个节点设固定 z-index(会堆满 1001/1002/1003…),而应利用 DOM 结构与层叠上下文特性:
立即学习“前端免费学习笔记(深入)”;
- 让每个
.tree-node自身成为层叠上下文(加position: relative) - 其内部的下拉面板(
.tree-node__menu)用z-index: 1即可,因为只跟同级兄弟比 - 父节点的
z-index只需略高于其直接容器(如.tree-node__children),不需要全局唯一 - 避免用 JS 动态计算并设置
z-index—— 这破坏了 BEM 的声明式原则,也难调试
真正容易被忽略的是:**z-index 的有效性永远取决于它是否处在同一个层叠上下文中**。写再多 .block--urgent { z-index: 999999 },如果块没 position,或者被某个中间父级截断了上下文,它就只是个被忽略的注释。


















