上个月有位读者给我发来一个页面,问我为什么别人做的卡片总有一种高级的磨砂质感,自己照着写却像一块脏玻璃。我让他把代码发过来,一眼就看出问题:他只给背景加了半透明白色,却不知道真正让背景“糊”起来的属性是backdrop-filter: blur()。也就是这一行,把普通半透明卡片变成了真正的毛玻璃模糊效果。今天这篇文就把这个效果掰开揉碎讲清楚,从原理到参数、从兼容性到性能优化,顺手把CSS里那些绕不开的点——选择器、居中、字体、动画、表格样式——用同一个场景串起来。想做出高级感页面但不知道从哪下手的同学,这篇应该够你练一阵子了。
1. 毛玻璃模糊效果到底是什么:设计流行与实现拆解
1.1 为什么现在到处都在用毛玻璃
相信你多少见过这种页面:半透明的白色面板压在彩色图片上,面板背后的图案被均匀打散,边缘还有一道细细的高光,像真实世界里的磨砂玻璃。这种风格在国内常叫毛玻璃效果,英文里叫 Glassmorphism。苹果在iOS 7之后大规模采用,macOS的侧边栏、Windows的亚克力效果、各类大厂的后台界面,都能看到类似设计。
我自己的观察是,这几年新出来的独立开发者和工具类产品尤其喜欢用它,原因很实在:成本低、见效快。扁平化设计确实干净,但层次基本靠投影和色块硬撑,稍不留神就显得寡淡;毛玻璃则在背景和内容之间加了一个半透明的“空气层”,用户既能感知页面底层的信息,又能看清上层的内容,整体氛围柔和很多。对前端来说,它不需要切图,不需要引入图片素材,几个CSS属性就能让页面显得精致,自然受欢迎。
1.2 一层毛玻璃,拆开其实是四层
很多新手以为毛玻璃就是“给背景加个半透明遮罩”,其实真相更复杂一点。一张能看的毛玻璃卡片,至少由四层结构组成:
- 底层内容:真正被压在下面的图片、图表、文字,浏览器先把它渲染出来。
- 半透明层:卡片自身的背景,通常写成
rgba(255, 255, 255, 0.2),作用是给玻璃一个基础色调。 - 模糊层:
backdrop-filter: blur(12px),负责把“卡片背后的内容”模糊掉,这是毛玻璃的核心。 - 高光层:
border: 1px solid rgba(255, 255, 255, 0.3),模拟玻璃边缘的反光,外面再挂一层box-shadow把卡片从背景里托起来。
这里有一个非常关键、也最容易被搞混的点:backdrop-filter和filter是两回事。filter是给元素自己的内容加滤镜,你把滤镜加在图片上,糊的就是图片本身;backdrop-filter是给“这个元素背后的东西”加滤镜,你看到的模糊,是透过这张半透明玻璃去看它身后的场景。生活里类比一下:filter是给照片本身加滤镜,backdrop-filter是给照片前面的玻璃板加磨砂。
注意:
backdrop-filter只作用于元素背后已经绘制好的内容。如果你给卡片设置完全不透明的背景,模糊结果会被遮住,肉眼根本看不到。
2. 五步写出第一个毛玻璃卡片
2.1 页面结构与背景准备
先用最简单的例子跑通。HTML 结构不需要复杂,一个背景舞台,一张玻璃卡片,就够了。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS毛玻璃卡片</title> <link rel="stylesheet" href="style.css"> </head> <body> <section class="page"> <div class="glass-card"> <h2>毛玻璃卡片</h2> <p>这是一张压在渐变背景上的半透明卡片。如果你在下方放一张真实图片,它的图案会透过卡片形成柔和的模糊效果。</p> </div> </section> </body> </html>这里有个小提醒:毛玻璃想看出效果,底层背景必须足够“花”。我见过有人把背景设成纯白,然后跑过来问我为什么模糊看不出来——纯白背景模糊之后还是白色,当然什么都看不出来。练习的时候建议用渐变色、风景图或者带纹理的背景,效果一目了然。
2.2 核心CSS与居中排版
CSS 部分我分成两块写,第一块是背景舞台,第二块是玻璃卡片本身。
* { margin: 0; padding: 0; box-sizing: border-box; } .page { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); overflow: hidden; } .glass-card { width: 340px; padding: 32px 24px; border-radius: 20px; background: rgba(255, 255, 255, 0.2); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.3); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); }逐个说下关键选择。display: flex配合justify-content: center; align-items: center;是现在最常用的水平垂直居中方案,比margin: 0 auto加position: absolute那套老写法省心很多,而且子元素不脱离文档流。min-height: 100vh让舞台撑满一屏,确保卡片处在视觉中心。
玻璃卡片里,background: rgba(255, 255, 255, 0.2)是半透明层,透明度我取0.2,这个值在浅色背景下既能透出底层景色,又不会让文字看不清。backdrop-filter: blur(12px)是模糊层,12px是常用的起步值。border加了一圈半透明白边,模拟玻璃边缘厚度;box-shadow给卡片底部压了一道深色阴影,这样玻璃才有“悬浮”感。如果你把阴影去掉,卡片会像贴在背景上的一张膜,立体感差很多。
2.3 为什么必须具备半透明背景
这一节值得单独讲,因为真的是重灾区。backdrop-filter的输入是“元素背后的渲染结果”,但输出还要跟元素自身的背景层叠加。如果元素背景是不透明的白色,模糊后的结果确实计算出来了,但会被这层白色完全盖住,你什么都看不到。
所以写毛玻璃效果,rgba()是绕不开的基础。透明度一般控制在0.15到0.6之间。低于0.15,玻璃的通透感有了,但文字可读性会出问题;高于0.6,模糊又几乎看不见,退化成普通半透明面板。我通常先在0.25左右起手,再根据背景明暗调整。顺便提一句,transparent背景虽然也能看到模糊,但玻璃的质感很弱,不建议新手用。
3. 参数是调出来的,不是抄出来的
3.1 blur之外还有三张牌:saturate、brightness、contrast
很多人写完blur(12px)就停了,然后觉得效果“还行但说不上高级”。问题通常出在色彩上:背景被模糊之后,颜色会发灰、变脏。真实世界里的磨砂玻璃并不会让颜色变灰,它只是把细节磨掉,色彩饱和度依然保留,甚至因为光线的漫反射还更柔和通透。
backdrop-filter支持叠加多个滤镜函数,用空格分隔就行:
.glass-card { backdrop-filter: blur(16px) saturate(180%) brightness(1.1); }saturate(180%)把背景饱和度拉高,抵消模糊带来的灰蒙感,这是我数值上最依赖的一个参数。brightness(1.1)稍微提亮,适合深色背景或夜间模式。contrast(1.05)用得少,但在暗色玻璃上能明显提升层次,可以按需加。
这三个函数和blur之间是顺序生效的,blur在前还是saturate在前,视觉效果会略有差异。我习惯把blur放最前面,先把形状摸糊,再做色彩补偿,逻辑更顺。
3.2 不同场景的参数参考表
我知道很多读者喜欢直接抄参数,这里给一张我平时调项目时常用的参考表,但请把它当起点,不要当公式。不同背景图上,同样的参数光影变化会很大。
| 使用场景 | blur 半径 | saturate | 背景透明度 | 备注 |
|---|---|---|---|---|
| 固定导航栏 | 16px-24px | 180% | 0.6-0.75 | 文字清晰度优先 |
| 悬浮卡片/磁贴 | 10px-16px | 150% | 0.2-0.35 | 通透感优先 |
| 弹窗/抽屉 | 20px-30px | 200% | 0.4-0.6 | 强调层次隔离 |
| 移动端底部操作栏 | 12px-20px | 150%-180% | 0.5-0.7 | 兼顾性能消耗 |
以弹窗为例,背景透明度我有时会压到0.6。原因是弹窗后面的内容复杂,如果玻璃太透明,用户注意力会被底层干扰;但如果你完全用不透明背景,又失去了毛玻璃的意义。0.5附近是个平衡点,再配合大半径模糊,视线会自然聚焦到弹窗上。
3.3 鼠标移入事件:把玻璃做成“活的”
毛玻璃卡片如果没有交互,总感觉少了一口气。CSS里最常用的鼠标移入事件就是:hover,你可以让鼠标移入时玻璃从“模糊”变成“更透”,同时加一点位移动画,手感会非常跟手。
.glass-card { transition: backdrop-filter 0.3s ease, background 0.3s ease, transform 0.3s ease; } .glass-card:hover { -webkit-backdrop-filter: blur(6px) saturate(160%); backdrop-filter: blur(6px) saturate(160%); background: rgba(255, 255, 255, 0.35); transform: translateY(-6px) scale(1.02); }这段代码里,blur从12px降到6px,背景透明度从0.2升到0.35,玻璃在鼠标经过时“变清晰了”,配合translateY(-6px)让卡片轻轻上浮,交互反馈很明确。要注意的是,transition需要同时给backdrop-filter和background,如果只给一条,动画会显得突兀。另外,部分旧版浏览器需要给transition的条目也加上-webkit-前缀,写的时候别省。
4. 最容易翻车的几个问题:兼容性与排查
4.1 问题速查表
毛玻璃效果在桌面端现代浏览器基本没戏,但移动端和特定场景下翻车概率不低。下面这张表是我这些年遇到过的高频问题,按“现象、原因、解法”整理。
| 现象 | 原因 | 解法 |
|---|---|---|
| 毛玻璃没有任何效果 | 浏览器不支持,或没加-webkit-前缀 | 用@supports做降级,并写双前缀 |
| 只有半透明背景,背景没有模糊 | 元素背景不透明,或祖先有transform/filter创建新层叠上下文 | 背景改成rgba(),检查祖先样式 |
| 固定导航栏下方内容不模糊 | fixed元素的包含块被祖先的transform改变 | 把导航栏放到body顶层,祖先别用transform |
| 模糊边缘出现白边或锯齿 | 元素边界与背景合成的抗锯齿处理不佳 | 给元素加border-radius,内部配合overflow: hidden |
| iOS Safari 上失效 | 旧版需要-webkit-前缀 | 两个前缀都写上,用标准语法 |
| 安卓低端机明显卡顿 | 大面积实时模糊开销大 | 缩小模糊区域,降低blur半径,优化背景层 |
4.2 用 @supports 做优雅降级
兼容性最稳妥的办法,不是去写一堆if判断,而是用 CSS 原生的@supports。原理很简单:先给不支持毛玻璃的浏览器一个高透明度背景,保证可读性;再在支持的环境里升级成真正的毛玻璃。
.glass-card { background: rgba(255, 255, 255, 0.75); } @supports (-webkit-backdrop-filter: blur(12px)) or (backdrop-filter: blur(12px)) { .glass-card { background: rgba(255, 255, 255, 0.25); -webkit-backdrop-filter: blur(12px) saturate(160%); backdrop-filter: blur(12px) saturate(160%); } }这个降级方案的好处在哪?如果浏览器不认识backdrop-filter,它会把@supports里的整段规则忽略掉,直接用外层的高透明度白色背景。用户看不到模糊,但也不会因为玻璃太透而读不清文字。这是我在生产环境里最常用的兜底写法。
4.3 排查时先分清是“不支持”还是“被遮挡”
我见过不少同学一遇到毛玻璃不生效,就归咎于浏览器兼容性。其实大多数情况是“被遮挡”而不是“不支持”。打开开发者工具,定位到卡片元素,看看backdrop-filter是不是被划了删除线,或者直接搜一下这个属性确认是否被浏览器识别。
有一个容易忽略的坑在祖先元素的overflow: hidden上。如果祖先容器把卡片裁切了,backdrop-filter的渲染区域会被截断,视觉上看起来就像是模糊没生效或者边缘坏了。解决方法通常是给卡片自身加border-radius和overflow: hidden,但要注意别跟父级的裁切叠加出奇怪的效果。真遇到,我的经验是给玻璃卡片包一层专门负责裁切的子元素,让模糊和裁切各管各的,互不干扰。
5. 进阶:让毛玻璃从“能用”变“好看”
5.1 加一层噪点,去掉“塑料感”
纯backdrop-filter做出来的玻璃,在色彩过渡很平滑的背景上容易显得太干净,甚至有点假。真实玻璃不是完美均匀的,它有细微的颗粒。要还原这种感觉,可以叠一层很淡的噪点纹理。
.glass-card { position: relative; } .glass-card::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0.05; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }这里用了::after伪元素加一段内联的 SVG 噪点图,opacity只开到0.05。千万别贪,超过0.08卡片就会显得脏。pointer-events: none一定要写,否则这层伪元素会挡住鼠标事件,按钮就点不动了。
5.2 多块玻璃叠放与层级管理
一个页面往往不止一张玻璃卡片。当多块玻璃叠在一起,z-index和层叠关系就成了新的问题。backdrop-filter会模糊自己下方的所有内容,包括其他玻璃层。所以如果两层玻璃面板重叠,上面的会模糊下面的,看起来就像两层真实玻璃叠在一起。
我一般这样管理层级:导航栏给z-index: 100,普通卡片给10,弹窗给1000,各自留出足够余量。需要注意,z-index只对定位元素和 flex 子元素生效。如果你在 flex 容器里用z-index控制排序,是可行的;但要是元素没有position,写再大的z-index也没用。这是新手最容易忽略的地方。
5.3 性能优化:别让玻璃拖垮页面
浏览器会给应用了backdrop-filter的元素单独创建合成层,每一帧都要重新采样和模糊背后的内容。如果你在页面里铺了十几个大面积模糊卡片,在移动端必卡。我自己在低端安卓机上实测,两三个中小面积卡片没问题,一旦全屏模糊再加滚动,掉帧会非常明显。
几条优化经验:
- 固定区域比全屏好用。导航栏、卡片、弹窗是毛玻璃的主战场,不建议大面积铺满。
blur半径别盲目上30px,半径越大,GPU 参与计算的像素量越大。- 不要在模糊元素上做频繁动画。如果一定要动,用
transform和opacity动画,它们不触发backdrop-filter的实时重算。 - 可以给个别元素写
will-change: backdrop-filter提前告知浏览器,但别全局滥用,否则内存占用更严重。 - 背景层尽量简单。如果背景本身是一张高分辨率风光图加多层渐变,模糊区域的计算压力会成倍增加。
6. 从一个毛玻璃项目,串起CSS入门到精通的路线
6.1 基础能力:选择器、盒模型、居中
毛玻璃卡片虽然看起来是单个效果,但它几乎覆盖了CSS最核心的基础知识。class类选择器负责选中卡片,.page .glass-card后代选择器负责限定范围,::after伪元素负责叠噪点;padding、border、border-radius、box-shadow全都是盒模型的一部分;display: flex加justify-content: center是目前最实用的居中方案。
我经常跟新手说,不要按顺序背CSS,而是找一个像毛玻璃这样的小项目,每解决一个问题就会被迫去查选择器、盒模型、定位。等你把这个卡片做出来,这些基础已经在实践中长在脑子里了,比抄十遍笔记都牢。
6.2 文字细节:字体、删除线、渐变文字、超出省略
玻璃卡片内部通常要放文字,排版细节决定质量。字体族建议用系统字体栈;价格场景里的原价可以用删除线;描述文字超过两行要省略,目前最常用的是-webkit-line-clamp。
.glass-card h2 { font-family: "PingFang SC", "Microsoft YaHei", sans-serif; font-size: 22px; font-weight: 600; } .glass-card .price-old { text-decoration: line-through; color: rgba(0, 0, 0, 0.4); } .glass-card .desc { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }如果你还想要一个更吸睛的标题,可以让文字做渐变效果。原理是用背景渐变填充文字,再裁切到文字形状上:
.text-gradient { background: linear-gradient(90deg, #fff, #a0c4ff); -webkit-background-clip: text; background-clip: text; color: transparent; }这个技巧放在毛玻璃卡片上格外好看,因为玻璃本身已经是半透明的,再叠加一个渐变文字,层次会非常丰富。
6.3 毛玻璃容器里的表格和优惠券样式
毛玻璃不只用于卡片,表格容器同样适用。表头用更高的透明度加模糊,会形成一种“表头浮在内容上”的效果;行悬停时把背景提亮,交互反馈很自然。
.glass-table { backdrop-filter: blur(10px); background: rgba(255, 255, 255, 0.15); border-collapse: separate; border-spacing: 0; } .glass-table th { background: rgba(255, 255, 255, 0.3); backdrop-filter: blur(6px); } .glass-table tbody tr:hover { background: rgba(255, 255, 255, 0.2); transition: background 0.2s; }如果你还想把毛玻璃卡片做成优惠券,两个半圆缺口是经典样式。用mask实现镂空,比堆背景渐变更灵活:
.mask-coupon { -webkit-mask: radial-gradient(circle at 12px 50%, transparent 12px, #000 12.5px) left / 24px 100% no-repeat, radial-gradient(circle at calc(100% - 12px) 50%, transparent 12px, #000 12.5px) right / 24px 100% no-repeat, linear-gradient(#000, #000) center / calc(100% - 48px) 100% no-repeat; mask: radial-gradient(circle at 12px 50%, transparent 12px, #000 12.5px) left / 24px 100% no-repeat, radial-gradient(circle at calc(100% - 12px) 50%, transparent 12px, #000 12.5px) right / 24px 100% no-repeat, linear-gradient(#000, #000) center / calc(100% - 48px) 100% no-repeat; }这段 mask 由三层组成:左右各切出一个透明半圆,中间用黑色矩形盖住剩余区域。半透明背景和backdrop-filter保留在未被裁切的部分,缺口处则完全镂空,底部背景直接透出来,优惠券的形态就出来了。注意给-webkit-前缀,移动端 Safari 认得它。
6.4 学习建议:用项目驱动代替死记硬背
我见过两类学习者。一类抱着厚厚的CSS书,从选择器一路背到动画,合上书还是不会写页面;另一类上来就想做个毛玻璃卡片,遇到问题翻文档、查属性,两三天就把它吃透了。我的建议是,尽量做第二种人。把毛玻璃效果当一个小项目,拆成背景、模糊、边框、投影、噪点、交互、兼容性,每解决一个小点就吃透几个属性。一个项目做完,选择器、盒模型、定位、伪元素、滤镜、渐变、动画、响应式、性能优化,基本都碰了一遍,而且每个知识点你都记得住为什么。
换个说法,CSS不是一门需要“学完才能用”的语言,而是一门“在用的时候学”的手艺。毛玻璃效果恰好是入门阶段性价比最高的练手项目之一:视觉反馈足够明显,技术栈足够综合,踩坑的点也足够典型。
最后说点个人体会。毛玻璃效果真正值钱的地方不在那一行backdrop-filter,而在你愿不愿意花时间去调:透明度高一点是不是更像玻璃?边框高光用0.3还是0.5?阴影的模糊半径要多大才能托起层次?我建议你拿到代码之后,把blur从0一步步推到40,再左右拖动saturate,用眼睛记住那种变化,下次再设计页面时就能凭直觉给出合适的值。另一个小技巧:调试时把多个参数拆开,先只保留blur,确认背景模糊到位了,再加上saturate和brightness,这样出问题能快速定位。至于滥用的问题,我也踩过坑——满屏毛玻璃看得人头晕,最后还是收敛到导航栏、卡片、弹窗这几个局部区域。克制一点,玻璃才高级。