z-index只对定位元素生效,bem块必须显式设position;需用css变量统一管理z-index值,禁用硬编码和inherit/unset;递归结构应利用dom嵌套分层而非数值堆叠。

z-index只对定位元素生效,BEM块必须显式设position
很多人给 .modal 写了 z-index: 1000 却发现没用,打开开发者工具一看——z-index 属性灰掉了。根本原因是:BEM块默认是 position: static,而 z-index 在 static 元素上完全无效。
必须让块自己创建层叠上下文,才能让内部的 z-index 有作用范围。这不是“加个类”的事,而是结构前提:
-
.modal必须带position: fixed或position: relative(哪怕不偏移) -
.dropdown推荐用position: relative,避免脱离视口影响滚动锚点 - 千万别只给子元素(如
.modal__overlay)设z-index,却不给.modal设position—— 子元素的z-index直接被忽略
每个BEM Block应独立创建层叠上下文,避免隐式干扰
BEM块要“自包含”,但实际中常因父容器意外创建新层叠上下文,导致整个块的 z-index 失效。比如:
- 父容器写了
transform: translateY(0)→ 隐式创建新上下文,.modal的z-index: 1000只在它内部比大小,盖不住同级的.sidebar -
.sidebar加了opacity: 0.99→ 同样触发新上下文,即使.modal值设到 9999 也出不去 -
.card用了will-change: transform→ 也是隐式上下文杀手
解决办法很直接:Block根元素主动、明确地创建上下文,不依赖外部。用 position + z-index 组合,不用 opacity、filter 等副作用属性做“视觉微调”。
用CSS变量统一管理z-index值,禁止硬编码数字
写 z-index: 9999 是最典型的反模式。它不可维护、无法推演、一改全崩。BEM不是命名规范,是约束边界——z-index 的值源必须唯一且语义化:
- 在
_zindex.scss或:root中定义:--z-modal: 1000、--z-dropdown: 100、--z-tooltip: 200 - 每个Block只用变量:
.modal { z-index: var(--z-modal); } - 子Element用相对值:
.modal__overlay { z-index: calc(var(--z-modal) - 1); } - 禁用
z-index: inherit或z-index: unset—— 这等于把控制权交出去,BEM就失效了
树形结构或动态嵌套时,用结构层级代替数值堆叠
像 .tree-node 这种递归块,如果每个展开节点都设 z-index: 1001、1002、1003…,很快就会撞上限、难调试、违反BEM声明式原则。
正确做法是利用DOM嵌套关系和层叠上下文天然分层:
- 每个
.tree-node自身设position: relative,成为独立上下文 - 它的下拉菜单
.tree-node__menu只需z-index: 1—— 因为只跟同级兄弟比 - 父节点的
z-index只要比其容器高即可(如.tree-node__children是z-index: 0,那父节点设1就够) - 绝对不要用JS动态算
z-index并写进style —— 这会让样式逻辑散落在HTML和JS两端,BEM的边界就塌了
真正难的不是写多少行CSS,而是守住“每个块只管自己上下文”的那一道线。一旦跨块去猜、去覆盖、去抢高度,z-index就从工具变成债务。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











