CSS 毛玻璃效果:backdrop-filter 一行实现 iOS 质感
做前端的人一定遇到过这种需求:导航栏要半透明模糊,弹窗背景要磨砂玻璃,视频封面上的标题文字要有一层朦胧底色。以前这些效果都要靠设计师切图,或者用伪元素加一张模糊过的背景图凑出来。
现在 CSS 有一个属性可以直接做这件事:backdrop-filter。一行代码,不用切图,不用伪元素。
这篇文章把它的用法、实战场景和容易踩的坑一次讲清楚。
先看传统做法有多麻烦
想在不支持 backdrop-filter 的年代做毛玻璃,常见写法是这样:
.glass-card {
position: relative;
overflow: hidden;
}
.glass-card::before {
content: '';
position: absolute;
top: -20px;
left: -20px;
right: -20px;
bottom: -20px;
background: url('bg.jpg') center / cover;
filter: blur(20px);
z-index: -1;
}思路是用伪元素铺一层背景图,再对这张图做模糊。问题是:背景图要单独维护,尺寸要手动同步,层级要算清楚,每加一个毛玻璃卡片就要复制一套。背景一换,伪元素也得跟着换。
换成 backdrop-filter,整段代码可以缩成这样:
.glass-card {
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.2);
}不需要背景图,不需要伪元素。元素背后的东西是什么,它就模糊什么。页面滚动、背景变化,模糊效果实时跟着变。
backdrop-filter 到底做了什么
一句话:它对元素背后的区域应用滤镜,不影响元素自己的内容。
注意是“背后”。元素自己的背景色、边框、文字都不受这个属性影响。它模糊的是这个元素“压住”的那一层画面。
这一点和 filter 容易混。区别很简单:
filter: blur() 模糊的是元素自己的内容,包括文字和子元素。
backdrop-filter: blur() 模糊的是元素背后的东西,元素自己的内容保持清晰。
毛玻璃要的是后者。
基础用法:一个毛玻璃卡片
HTML 部分:
<div class="glass-card">
<h2>毛玻璃卡片</h2>
<p>背景是动态的,模糊效果跟着底层内容实时变化</p>
</div>CSS 部分:
.glass-card {
/* 核心:模糊背后的内容 */
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
/* 半透明背景,让模糊能透出来 */
background: rgba(255, 255, 255, 0.12);
/* 细边框增加层次感 */
border: 1px solid rgba(255, 255, 255, 0.15);
/* 圆角和内边距 */
border-radius: 16px;
padding: 32px;
color: #fff;
}有一个地方必须注意:background 不能是纯色不透明。如果写成 background: white,背后被完全遮住,模糊就看不到了。
多个滤镜叠加,效果更高级
backdrop-filter 可以一次写多个函数,用空格分开:
.glass-card {
backdrop-filter: blur(20px) brightness(1.1) saturate(1.2);
-webkit-backdrop-filter: blur(20px) brightness(1.1) saturate(1.2);
background: rgba(255, 255, 255, 0.08);
}常用的几个函数:
| 函数 | 作用 | 适用场景 |
|---|---|---|
| blur(20px) | 模糊,核心函数 | 毛玻璃效果 |
| brightness(1.1) | 提亮 | 让模糊区域更亮 |
| saturate(1.2) | 提高饱和度 | 让颜色更鲜艳 |
| contrast(1.1) | 提高对比度 | 让上层文字更清晰 |
| hue-rotate(10deg) | 色相旋转 | 创意滤镜 |
注意一点:这些函数会按顺序执行。写在前面的先算,后面的基于前面的结果再算。顺序不同,最终效果可能不一样。
三个实战场景
场景一:固定导航栏
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 16px 24px;
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
background: rgba(255, 255, 255, 0.08);
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
z-index: 100;
}页面往下滚,导航栏底下的内容会变成模糊的一层。苹果官网的顶部导航就是这个做法。
场景二:模态框遮罩
.modal-overlay {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
background: rgba(0, 0, 0, 0.3);
}
.modal {
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 40px;
max-width: 400px;
width: 90%;
}inset: 0 是 top / right / bottom / left 四个方向的简写,现代浏览器都支持。
弹窗打开时,背后整个页面变模糊。用户视线自然集中到弹窗上,比单纯的半透明遮罩更舒服。
场景三:图片上叠加标题
.hero {
position: relative;
}
.hero-title {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 40px 20px;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
background: rgba(0, 0, 0, 0.2);
color: #fff;
}图片颜色深浅不一的时候,直接写白字可能看不清。加一层毛玻璃底,文字始终有对比度。
五个容易踩的坑
坑一:Safari 需要加 -webkit- 前缀
这一点很多人搞错。Safari 长期只支持带前缀的 -webkit-backdrop-filter,无前缀写法是后来才加上的。为了覆盖更多版本,两个都写最稳:
.glass {
-webkit-backdrop-filter: blur(20px);
backdrop-filter: blur(20px);
}顺序建议把 -webkit- 写在前面,无前缀写在后面。这样新浏览器用标准写法,老 Safari 也能识别。
坑二:背景必须半透明
前面提过,这里再强调一次。backdrop-filter 只对元素背后的东西生效。如果你的元素背景是不透明的,那就什么都看不到。
/* 错误写法:背景不透明,看不到模糊 */
.glass {
backdrop-filter: blur(20px);
background: #fff;
}
/* 正确写法:用 rgba 或 hsla 给个透明度 */
.glass {
backdrop-filter: blur(20px);
background: rgba(255, 255, 255, 0.15);
}坑三:祖先元素带 filter 会让它失效
这是一个容易被忽略的问题。如果毛玻璃元素的某个祖先元素上写了 filter 或 backdrop-filter,模糊可能会出错,或者完全不生效。
原因是这些属性会创建新的包含块和层叠上下文,backdrop-filter 拿到的“背后画面”会变。
排查的时候,从当前元素往上查祖先,看看有没有 filter、transform、opacity 小于 1 这类会创建新上下文的值。
坑四:会创建包含块,影响 fixed 定位
backdrop-filter 不是 none 的时候,元素会成为内部 position: fixed 子元素的包含块。
也就是说,如果你给一个容器加了毛玻璃,容器里面再用 position: fixed,这个 fixed 是相对容器定位的,不是相对视口。这一点在弹窗组件里很容易出问题。
坑五:性能开销不小
毛玻璃的本质是多加一层合成。浏览器要把背后的内容单独渲染出来,做模糊,再合成回去。
页面上有一两个小面积毛玻璃,问题不大。如果同时出现十几个大面积毛玻璃元素,或者毛玻璃在滚动过程中频繁重绘,低端手机和旧设备就会掉帧。
几个优化方向:
减少毛玻璃元素的数量和面积。
避免在动画里频繁改变 backdrop-filter 的值。
毛玻璃层加 will-change: backdrop-filter 要谨慎,用多了反而吃内存。
移动端可以降级成纯半透明背景,不做模糊。
浏览器支持情况
目前的主流浏览器都支持 backdrop-filter:
Chrome 76 及以上
Edge 79 及以上
Firefox 103 及以上
Safari 9 及以上,但需要 -webkit- 前缀
iOS Safari 9 及以上,同样需要前缀
不支持的浏览器会直接忽略这个属性。所以最好给一个不透明或半透明的背景色做兜底,效果降级但页面不会坏。
小结
backdrop-filter 把毛玻璃效果从“切图 + 伪元素”变成了“一行 CSS”。核心用法记住这几点:
用 backdrop-filter: blur(20px) 模糊背后的内容。
配 rgba 半透明背景,模糊才看得出来。
Safari 要写 -webkit-backdrop-filter。
可以叠加 brightness、saturate 等函数调出高级感。
注意性能和祖先元素的影响,别在大面积滚动区域堆太多毛玻璃。
导航栏、模态框、图片标题、卡片,这些常见场景都能直接用。三行 CSS,就能做出接近 iOS 原生的磨砂质感。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!