z-index不生效的根本原因是元素未创建层叠上下文;需为BEM块根元素显式设置position(如relative/fixed),避免父容器用transform/opacity隐式触发新上下文,并采用语义化CSS变量管理层级。

z-index不生效?先查元素有没有创建层叠上下文
写了 z-index: var(--z-modal) 却盖不住隔壁组件,八成是元素压根没进入层叠上下文。BEM 块(如 .modal)默认是 position: static,而 z-index 在 static 元素上完全被忽略——开发者工具里该属性会变灰,Computed 面板显示 auto。
必须让 Block 根元素自己显式创建上下文:
-
.modal要加position: fixed或position: relative(哪怕不偏移) -
.dropdown推荐用position: relative,避免脱离视口影响滚动锚点 - 千万别只给子元素(如
.modal__overlay)设z-index,却不给.modal设position——子元素的z-index直接被浏览器无视
父容器加了 transform 或 opacity,子元素 z-index 就“出不去”
父容器加了 transform: translateY(0)、opacity: 0.99 或 will-change: transform,会隐式触发新层叠上下文。结果就是:.modal 的 z-index: 1000 只在它内部比大小,根本出不去这个父容器,盖不住同级的 .sidebar。
这不是 BEM 命名的问题,而是结构前提被破坏了:BEM 块应自主、明确地创建上下文,不依赖外部环境。
立即学习“前端免费学习笔记(深入)”;
- 视觉微调(比如轻微位移或半透明)优先用
top/left或background-color: rgba(),避开副作用属性 - 若必须用
transform做动画,把需要提层的元素(如弹窗挂载点)提前“提”到更高层级容器(如#overlay-root),并确保该容器已设position: relative - Chrome DevTools → Elements → 逐级点击父节点,右侧面板 Layout 标签页留意「Stacking Context」是否突然变成 Yes
BEM 块内 z-index 值该从哪来?别写死在 :root
把 --z-modal: 1000 写死在 :root 是最危险的起点。一旦某个模块升级这个值,所有引用它的组件(包括按钮、卡片、Toast)都会意外被顶起。
- 按功能定义语义化变量:
--z-header、--z-dropdown、--z-modal、--z-toast,统一放在单独的_zindex.scss中 - 每个块只使用这些变量,不硬编码数字;修改一处,全站响应
-
.modal__overlay这类子元素用相对偏移:z-index: calc(var(--z-modal) - 1),而非固定值 - 禁止在 Modifier 类(如
.modal--fullscreen)里覆盖z-index——它只该改颜色、尺寸等视觉属性,层级属于 Block 职责
树形控件或递归组件里的 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 的声明式原则,也难调试
真正难的不是堆数字,而是看清谁在哪个盒子里比大小。DOM 路径上只要出现一个 transform、opacity 或 filter,就得停下来问一句:这个“盒子”,是不是我真想让它存在。


















