前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库CSS filter 层叠上下文 fixed 子元素影响
CSS动画与视觉

给父元素加了 filter,子元素的 fixed 定位为什么失效了?

父元素一旦设了 filter(哪怕是 filter: blur(0px) 这种看不出效果的值),它就会变成子元素 position: fixed 的包含块。本来 fixed 是相对于视口定位的,这时变成了相对于父元素定位,看起来就像 fixed 失效了。这是因为规范规定 filter 会创建新的包含块。

前端进阶之旅 · 一题精讲更新于 2026.09.29
CSS#动画与视觉#动画
先看核心答案读代码示例
理解线索

`filter` 的两个隐藏副作用

  1. 创建层叠上下文子元素的 z-index 被限制在父元素的层叠上下文内
  2. 改变包含块fixed 定位的子元素不再相对于视口,而是相对于父元素
  3. 同类属性transform、perspective、will-change、backdrop-filter 也有同样效果

即使 filter 的值在视觉上没有效果(比如 blur(0px) 或 opacity(1)),只要属性存在,副作用就在。

核心回答

先记住这个答案

position: fixed 正常情况下相对于视口定位,滚动页面时它始终固定在屏幕上。但如果它的某个祖先元素设了 filter,CSS 规范规定这个祖先会变成 fixed 元素的「包含块」。这时 fixed 实际上变成了相对于那个祖先定位,效果和 absolute 差不多——页面滚动时这个元素会跟着一起滚走。

  • filter 可改变后代 fixed 的包含块
  • 效果等同于 fixed 变成了 absolute
  • transform 等属性也可能改变包含块
  • 把浮层移出滤镜父级可恢复视口定位

一个导航栏失效的场景

假设页面有一个全局导航栏用了 position: fixed,平时它固定在顶部没有问题。某天有个需求要把页面整体变灰,在 .page-wrapper 上加了 filter: grayscale(1)。然后导航栏突然就跟着页面一起滚了。

复现 fixed 失效CSS
/* 页面容器加了 filter,导航栏 fixed 失效 */
.page-wrapper {
  filter: grayscale(1); /* 这行加上后导航栏就不固定了 */
}

.navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 1000;
  /* 现在它相对于 .page-wrapper 定位,不再相对于视口 */
}

删掉 filter: grayscale(1) 导航栏就恢复正常了。问题不在 z-index,也不在 position 的值,纯粹是包含块被 filter 改变了。

为什么 filter 会改变包含块

CSS 规范对 fixed 定位的包含块有一条特殊规则:如果某个祖先元素建立了新的包含块,fixed 就不再相对于视口定位。能建立新包含块的属性包括 transform、perspective、filter、backdrop-filter、will-change(当值是上述属性之一时),以及 contain: paint。

filter 之所以会这样,是因为浏览器对 filter 元素做了特殊的渲染处理——它需要先把元素和子元素画到一个离屏的画布上,再对画布做滤镜。这个离屏画布就是新的坐标系,fixed 定位的子元素在这个坐标系里计算位置,自然就不是相对于视口了。

这个行为和值无关。filter: blur(0px) 看起来什么都没做,但浏览器照样会走离屏渲染的流程,fixed 照样失效。

项目里怎么解决

最直接的办法是调整 DOM 结构,让 fixed 元素不在带 filter 的容器内部。

比如刚才的导航栏场景,把 <nav> 从 .page-wrapper 里挪出来,变成它的兄弟节点。灰度效果只加在 .page-wrapper 上,导航栏不受影响。

如果 DOM 结构改不了(比如在一个第三方组件里),可以考虑换个思路实现灰度效果。用 SVG filter 或者 mix-blend-mode 做覆盖层,就不会影响子元素的定位行为。

还有一种取巧的方式:如果只是想在整个页面上加灰度,把 filter 加在 <html> 元素上。<html> 是根元素,fixed 元素的包含块就是根元素本身,效果上和相对于视口定位是一样的。

回答前,多想一步

容易答错的地方

以为是 z-index 的问题
fixed 元素没有固定住,第一反应经常是去调 z-index。但包含块被改变之后,z-index 再高也没用——元素的位置计算基准变了,它在视觉上就是在错误的位置。
以为只有 transform 会让 fixed 失效
transform 是最广为人知的一个,但 filter、backdrop-filter、perspective、will-change 都有同样的效果。面试时只答 transform 而漏掉 filter 会显得理解不够全面。
试着用自己的话回答

面试官还会怎么问?

will-change: filter 也会让 fixed 失效吗?

会。will-change 的作用是告诉浏览器某个属性即将变化,浏览器会提前做准备——对于 filter 来说,准备工作就是创建离屏渲染环境,所以包含块同样会被改变。

filter 创建的层叠上下文和 z-index 创建的有什么区别?

效果一样,都是把子元素的层叠顺序限制在这个上下文内部。区别在于 z-index 需要配合 position: relative/absolute/fixed 才生效,而 filter 无条件创建——只要属性存在就行,不需要配合定位。

怎么检测页面上哪些元素创建了层叠上下文?

Chrome DevTools 的 Layers 面板可以看到所有合成层。3D View(在 More tools 里)可以看到层叠上下文的嵌套关系。也可以用 getComputedStyle 检查元素的 filter、transform、opacity 等属性是不是非初始值。

从一道题,走向一组知识

把知识连起来

动画与视觉

linear-gradient 里 0deg 是朝上还是朝右?角度怎么影响渐变方向?

父级 filter 会处理子元素绘出的渐变画面;渐变角度只改变图像本身,不会像滤镜那样建立层叠上下文。

动画与视觉

linear-gradient 里两个色标写在同一位置,为什么会出现硬边?

渐变相关的 CSS 效果不影响定位和层叠,和 filter 的副作用形成对比。

参考资料

  • CSS:动画与视觉参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 一个导航栏失效的场景
  3. 为什么 filter 会改变包含块
  4. 项目里怎么解决
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑