2026-10-03 更新:本文改用 Filter Effects Level 2 规范、CSS Color 4/5 规范、MDN 官方文档与 WCAG 2.2 官方说明重写,删去原先的本机实测数值;示例都是可直接复制的代码,并标明所依据的规范条款。
"毛玻璃"在 Web 上就是一个 CSS 属性:backdrop-filter。但真把它铺到全站之后,常见的反馈是"有的地方生效、有的地方没反应""字看不清了"。原因几乎都出在规范的几条硬性条件上——背景根本没有内容可模糊、或者祖先元素悄悄变成了"背景根"。本文按规范把条件和坑讲清楚,并给出可直接复制的示例。
一、真玻璃只有三件事
按规范,backdrop-filter 要生效必须同时满足:
- 元素本身有半透明的部分。Filter Effects Level 2 规范 §2 的原文说得很直接:The effect of the backdrop-filter will not be visible unless some portion of element B is semi-transparent.(除非元素某个部分是半透明的,否则看不出效果。)MDN 的表述是同一件事:因为它作用于元素背后的一切,要看到效果,元素或它的背景需要透明或部分透明。规范还补了一句:要创建"完整透出过滤后背景"的透明元素,用
background-color: transparent。 - 背后确实有内容。元素背后若只有纯色页面背景,模糊出来的还是同一片颜色,看不出差别。
- 没被祖先截断(下一节)。
属性取值为 none 或一个滤镜函数列表(blur()、brightness()、saturate() 等,也可以是 SVG 滤镜 url());初始值 none,不继承。
.glass {
background-color: rgb(13 17 23 / 35%); /* ← 半透明底,缺了这行就没有效果 */
backdrop-filter: blur(10px) saturate(140%);
}二、Backdrop Root:为什么"写了却不生效"
规范 §3 定义了 Backdrop Root(背景根):元素的 backdrop 图像是"从最近的祖先 Backdrop Root 起,按绘制顺序绘制到该元素为止的全部内容"展平成的 2D 缓冲。这意味着,模糊范围被最近的 Backdrop Root 截断。
规范 §3.2 列出了会形成 Backdrop Root 的情况:
- 文档根元素;
filter非none;opacity小于 1;mask/mask-image/mask-border/clip-path非none;backdrop-filter非none(即毛玻璃元素自己也会形成背景根,这就是"嵌套毛玻璃"退化的原因);mix-blend-mode非normal;will-change指定了上述任一属性。
MDN 给了一个典型的踩坑场景:父元素写了 opacity: 0.9,它就变成 backdrop root,子元素的 backdrop-filter 只会模糊"父元素与子元素之间"的内容——看起来像"没生效",其实是范围被截断了。
也有一个好消息:规范说明Backdrop Root 不会因为 z-index、fixed/sticky 定位或 transform 而形成(覆盖面比 stacking context 小),所以用容器做 transform 动画不会阻断子元素看到容器背后的背景。
三、连着来的两个副作用
规范 §2 的注释里说明:backdrop-filter 计算值不是 none 时,会创建 stacking context,并为 absolute/fixed 定位的后代创建 containing block(根元素除外),行为与 filter 属性一致。这意味着:
- 内部用
position: fixed弹出的子层,会以这个毛玻璃元素为参照,而不是视口——常见的"弹出层位置跑偏"就源于此; - 如果本来依赖
z-index的层级关系,加上毛玻璃后层级会重新按新的 stacking context 计算。
四、性能:规范怎么说
规范 §3.1 的动机一节解释了为什么要有 Backdrop Root 这个约束:如果 backdrop-filter 过滤"之前绘制的一切",每次都必须单独渲染一遍,会翻倍所需渲染时间,并可能需要两倍内存与 GPU 带宽;嵌套则指数级恶化。§3.2 的总结是:对所有触发 Backdrop Root 的元素,放松这个约束都会带来 CPU/GPU 内存与带宽的潜在翻倍。
⚠️ 需要明确的边界:规范与本节的官方文档都没有给出"一个页面能放几个 backdrop-filter"的数值阈值。任何具体数字都属于站点自测结论,不是规范结论。可操作的判断依据是"每个毛玻璃元素都会让浏览器多渲染一份背后的内容",所以固定不动的页面级表面(导航、侧栏、底栏)比列表项里的毛玻璃划算得多。
五、示例 1:最小的毛玻璃面板(带回退)
思路:默认给接近实色的底保证可读性,只有在浏览器确实支持 backdrop-filter 时才把底变透明并开启模糊;-webkit- 前缀给旧 Safari。
/* glass.css —— 外部样式表,只用 class,不含内联样式或 style 属性 */
.glass-panel {
/* 回退:不支持时用接近实色的底,保证文字对比度 */
background-color: rgb(13 17 23 / 92%);
color: #f0f6fc;
border-radius: 12px;
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.glass-panel {
background-color: rgb(13 17 23 / 35%); /* 半透明,效果才可见 */
-webkit-backdrop-filter: blur(10px) saturate(140%);
backdrop-filter: blur(10px) saturate(140%);
}
}<div class="glass-panel">面板内容</div>@supports 是 MDN 所说的"特性查询":用 property: value 形式检测浏览器是否支持某个声明,也可以用 and / or / not 组合。
六、示例 2:用一个数字调 alpha
透明度表达在 CSS Color 4 规范里是有定义的:<alpha-value> 可以是数字或百分比,省略时默认 100%,超出 [0,1] 的值在解析时被钳制而不是报错;rgb() 的现代语法允许斜杠分隔 alpha(rgb(R G B / <alpha-value>)),百分比里 0% 即 0.0、100% 即 1.0。
于是"调透明度"就是调一个变量:
/* toolbar.css —— 外部样式表,class 驱动 */
:root {
--glass-alpha: .28; /* 唯一旋钮:改这个数字即可 */
}
.glass-toolbar {
background-color: rgb(13 17 23 / 92%); /* 回退 */
color: #f0f6fc;
}
@supports (backdrop-filter: blur(1px)) {
.glass-toolbar {
background-color: rgb(13 17 23 / var(--glass-alpha));
backdrop-filter: blur(8px) saturate(140%);
}
}如果底色的"基色"是一个不透明值,也可以用 CSS Color 5 定义的 color-mix() 算出来:
.glass-card {
background-color: rgb(13 17 23 / 92%); /* 回退 */
}
@supports (background-color: color-mix(in srgb, red 50%, transparent)) {
.glass-card {
/* 基色占 35%,其余混入 transparent */
background-color: color-mix(in srgb, #0d1117 35%, transparent);
}
}color-mix() 的官方定义是:接受一组 <color> 并按给定色彩空间与比例混合;若总百分比小于 100%,结果颜色会被乘以 p1+p2 的 alpha——这正是"从一个不透明基色算出半透明表面"的规范依据。MDN 记载它自 2023 年 5 月起为 Baseline Widely available,但"多个颜色参数"的形式支持尚不广泛,示例只用两色形式。
七、示例 3:尊重系统的"降低透明度"
Media Queries Level 5 定义了 prefers-reduced-transparency,用于探测用户是否要求系统减少透明/半透明层次效果;取值 no-preference / reduce。MDN 标注它目前仍是 Experimental 且非 Baseline(Firefox、Safari 不支持),所以只能当增强回退,不能当作唯一回退手段。
@media (prefers-reduced-transparency: reduce) {
.glass-toolbar { background-color: rgb(13 17 23 / 96%); }
.glass-panel { background-color: rgb(13 17 23 / 96%); }
}八、代价:最先扛不住的是文字
半透明底意味着文字背后的颜色是不确定的,而对比度是可访问性里被官方量化过的指标。WCAG 2.2 的相关条文(W3C WAI 官方说明):
- SC 1.4.3 Contrast (Minimum),AA:正文文本与文本图像对比度至少 4.5:1;大号文本(约 18pt,或 14pt 粗体,约等于 24px / 18.5px)至少 3:1。官方同时说明:阈值不四舍五入(4.499:1 不达标),并且要按样式表给出的前景/背景色评估,而不是屏幕上抗锯齿之后的观感。
- SC 1.4.11 Non-text Contrast,AA:用于识别 UI 组件与状态、以及理解内容所必需的图形,与相邻颜色的对比度至少 3:1。
- SC 2.4.11 / 2.4.12 Focus Not Obscured:键盘聚焦的组件不得被作者内容完全遮挡;官方特别指出半透明叠层或带模糊/变暗效果的叠层也是遮挡来源,2.4.12(AAA)更进一步——即使聚焦组件仍部分可见,这种叠层也构成失败,并可能连带导致 1.4.11 与 2.4.13 失败。
- SC 2.4.13 Focus Appearance,AAA:焦点指示器要满足面积要求,且聚焦/未聚焦状态下同一像素的对比度至少 3:1。
落到实践上就是三条:毛玻璃面板上的文字要按"最坏情况"(背后是最亮的内容时)核算对比度;固定导航这类会盖住内容的表面,给足不透明度或加一层文字阴影;页面级固定毛玻璃要确认它不会盖住键盘焦点框。
九、跨浏览器要记住的两个事实
MDN 的浏览器兼容数据(browser-compat-data)给出了具体版本:
- Safari:无前缀名称自 Safari 18 起支持,而
-webkit-backdrop-filter自 Safari 9 起就有——所以旧 Safari 必须带前缀。 - Edge:
-webkit-前缀自 17 起、到 79 移除;无前缀自 79 起。 - Firefox:103 起支持,但在 Firefox 123 之前,GPU 厂商未知的系统上不支持(官方 bug 1867937 记录)。这类环境会命中你的回退分支——这正是回退必须"可读"而不是"糊成一片"的原因。
十、落地清单
- [ ] 每个毛玻璃表面都有半透明底(否则规范直接判定看不出效果);
- [ ] 检查祖先有没有
opacity < 1、filter、mask、clip-path、mix-blend-mode——它们会让毛玻璃"看起来没生效"; - [ ] 默认提供不透明的可读底色,
@supports通过后才降 alpha(顺序不能反); - [ ] 旧 Safari 带
-webkit-前缀; - [ ] 大量列表项不要逐项加毛玻璃(规范说明每个都会多渲染一份背景),优先用在固定表面;
- [ ] 面板上的文字按最坏背景核算 WCAG 对比度(4.5:1 / 大文本 3:1);
- [ ] 页面级固定毛玻璃不要遮住键盘焦点框(SC 2.4.11/2.4.12);
- [ ] 若用
color-mix()或prefers-reduced-transparency,都放进@supports/@media里做渐进增强。
参考来源
- W3C CSSWG, Filter Effects Module Level 2(§2 backdrop-filter 与半透明条件、§3 Backdrop Root、§3.1 性能动机)— https://drafts.fxtf.org/filter-effects-2/
- W3C CSSWG, Filter Effects Module Level 2(csswg 版本)(创建 stacking context 与 containing block)— https://drafts.csswg.org/filter-effects-2/
- MDN, backdrop-filter(生效前提、backdrop root 被父级 opacity 截断、Baseline 状态)— https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter
- MDN, filter — https://developer.mozilla.org/en-US/docs/Web/CSS/filter
- MDN browser-compat-data, css/properties/backdrop-filter.json(Safari/Edge 前缀与版本、Firefox 123 说明)— https://github.com/mdn/browser-compat-data/blob/main/css/properties/backdrop-filter.json
- W3C WAI, Understanding SC 1.4.3: Contrast (Minimum) — https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html
- W3C WAI, Understanding SC 1.4.11: Non-text Contrast — https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html
- W3C WAI, Understanding SC 2.4.11: Focus Not Obscured (Minimum) — https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html
- W3C WAI, Understanding SC 2.4.12: Focus Not Obscured (Enhanced) — https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-enhanced.html
- W3C WAI, Understanding SC 2.4.13: Focus Appearance — https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html
- W3C CSSWG, CSS Color Module Level 4(
<alpha-value>、斜杠 alpha 语法)— https://drafts.csswg.org/css-color-4/ - W3C CSSWG, CSS Color Module Level 5(
color-mix()定义)— https://drafts.csswg.org/css-color-5/ - MDN, color-mix()(总百分比小于 100% 时的 alpha 乘数、Baseline 状态)— https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix
- MDN, @supports — https://developer.mozilla.org/en-US/docs/Web/CSS/@supports
- MDN, prefers-reduced-transparency — https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-transparency
- MDN, isolation / background-blend-mode — https://developer.mozilla.org/en-US/docs/Web/CSS/isolation ・ https://developer.mozilla.org/en-US/docs/Web/CSS/background-blend-mode