z-index不生效主因是元素未创建层叠上下文;需确保元素显式设置position(如relative或fixed),并避免父容器因transform、opacity等触发隐式上下文。

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 来“微调”
父容器加了 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
CSS变量怎么定义才真可控
把 --z-modal: 1000 写死在 :root 是最危险的起点。一旦某个模块升级这个值,所有引用它的组件(包括按钮、卡片、Toast)都会意外被顶起。
正确做法是按功能域就近定义:
.modal { --z-element: var(--z-modal, 1000); z-index: var(--z-element); }.dropdown { --z-element: var(--z-dropdown, 950); z-index: var(--z-element); }- 数值预留间隙:相邻层级至少差 10(
--z-tooltip: 300,--z-modal: 900),方便后续插入新层 - 禁用
calc(var(--z-base) + 10)深度嵌套——旧版 Safari 对calc+var()支持不稳定
递归结构(如树形节点)的 z-index 怎么办
像 .tree-node 这种可能无限嵌套的块,不能靠硬编码 z-index: 1001、1002……堆叠。每个节点都应成为独立层叠上下文:
- 每个
.tree-node自身加position: relative - 其内部菜单(
.tree-node__menu)只需z-index: 1,因为只跟同级兄弟比 - 父节点的
z-index只需略高于直接容器(如.tree-node__children),无需全局唯一 - 绝对不要用 JS 动态计算并设置
z-index——这违背 BEM 声明式原则,也难调试和复现
真正容易被忽略的,是层叠上下文的“传染性”:一个看似无害的 opacity: 0.99 就能让整块 BEM 结构的 z-index 归零。别指望命名能救层级,得靠 position + z-index + 变量作用域三者咬合才稳。


















