filter 属性(包括 blur(0))会强制创建新的层叠上下文,使子元素 z-index 仅在内部生效而无法与外部同级元素比较层级。

filter 属性(哪怕只是 filter: blur(0))会强制创建新的层叠上下文,导致子元素的 z-index 失效——这不是 bug,是规范行为。
为什么 filter 会让 z-index 看似“失效”
只要一个元素的 filter 值不是 none,浏览器就必须为它新建一个层叠上下文(stacking context)。这意味着:它的所有子元素的 z-index 只在这个“盒子”内部起作用,无法和外部同级元素比高低。
常见现象包括:
- 下拉菜单被隔壁卡片盖住,即使菜单自身
z-index: 9999 - Tooltip 显示不全,边缘被父容器裁掉
- Modal 遮罩层压不住带
filter的 header
注意:filter: blur(0)、filter: opacity(1)、filter: drop-shadow(0 0 0 #000) 全部触发该行为——值为 0 不代表“没效果”,它照样建上下文。
立即学习“前端免费学习笔记(深入)”;
如何快速定位哪个 filter 在“截胡”层级
打开 Chrome DevTools → 选中被遮挡的元素 → 右侧 Computed 面板 → 搜索 stacking context:
- 逐级向上点父节点,直到找到第一个标有 “This element establishes a stacking context” 的祖先
- 点开它的 Computed 样式,确认
filter不是none;顺手检查opacity、transform、will-change是否也在作祟 - 临时在 Styles 面板里取消勾选该父元素的
filter,如果遮挡立刻消失,就坐实了问题
修复方案:绕过而非硬调 z-index
别再给子元素狂加 z-index: 999999,数字再大也出不了那个“结界”。真正有效的做法是结构层面解套:
- 如果
filter是为 hover 动画等非必需视觉效果,直接删掉最干净 - 必须保留毛玻璃等效果?把需要“突围”的元素(如
dropdown、tooltip)用position: fixed提出来,挂到<body>下,并用 JS 动态计算top/left(注意滚动和缩放偏移) - 若多个模块共用一个带
filter的容器,不如统一提升该容器自身的z-index(前提是它已设position: relative或类似),让它整体抬高 - 避免用
filter: blur(0)当“兼容占位符”——它和blur(1px)对层叠上下文的影响完全一致
特别注意 transform + filter 组合
两者叠加时,浏览器会强制新建合成层(compositing layer),层叠上下文的隔离性更强。例如:transform: translateY(0); filter: brightness(1); 看似什么都没变,但已构成双重上下文,调试时更容易误判源头。这种组合应尽量避免,除非明确需要硬件加速且已评估层级影响。
最常被忽略的一点:层叠上下文一旦建立,就不可撤销;你没法用子元素的 z-index “穿透”它——能做的只有调整结构、提升父级、或把关键元素移出这个上下文。


















