「做成 iOS 那种感觉」是一句没法执行的需求。它描述的是结果,不是方法。
试着拆一下。iOS 的界面之所以看起来「高级」,不是因为毛玻璃,而是因为它把空间关系表达得很清楚:哪一层在前面,哪一层在后面,光从哪来。玻璃只是这种关系最直观的载体。
具体到实现,我把它拆成三层。
第一层:背景不能是纯色
毛玻璃的价值来自它后面的东西。背景是一片纯白,backdrop-filter 就等于没有。
所以底层要先铺一层有变化的颜色。我用四个大面积的径向渐变:
.backdrop {
position: fixed;
inset: 0;
z-index: -1;
background: var(--bg);
overflow: hidden;
}
.orb-a {
position: absolute;
width: 58vw; height: 58vw;
top: -22vw; left: -14vw;
border-radius: 50%;
filter: blur(40px);
background: radial-gradient(circle at 40% 40%,
rgba(120, 178, 255, 0.55), transparent 68%);
}
几个要点:
- 颜色要淡。饱和度稍微一高,就从「高级」掉到「廉价」。
- 位置要偏。色块都堆在中心,看起来像 PPT 模板;让它们从边缘溢出来,才有「页面之外还有空间」的暗示。
- 再用一层噪点收尾。透明度 3% 左右,
mix-blend-mode: overlay。它几乎看不见,但能消掉渐变的塑料感——这是最容易被忽略、性价比最高的一步。
第二层:玻璃本身
毛玻璃的公式就四个属性:
.glass {
background: rgba(255, 255, 255, 0.56);
border: 1px solid rgba(255, 255, 255, 0.9);
-webkit-backdrop-filter: blur(28px) saturate(180%);
backdrop-filter: blur(28px) saturate(180%);
box-shadow:
0 8px 24px -6px rgba(16, 18, 27, 0.10),
inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
saturate(180%) 是关键。只做模糊的话,卡片会把后面的颜色糊成灰色,整体发闷;提高饱和度之后,透过来的颜色依然鲜明,才会有「玻璃」而不是「磨砂塑料」的感觉。
那个 inset 阴影是镜面高光——1px 的白色内阴影,模拟光打在玻璃上边缘的反射。没有它,卡片会和背景糊在一起,缺少厚度。
第三层:层次与动效
三层结构里最容易被做坏的是这一层:所有元素都加玻璃,于是没有层次。
我的规矩是:同一屏里最多两级玻璃。
- 导航栏和卡片是同级,用同一套参数;
- 页脚、目录这类次要元素降低不透明度,弱化存在感;
- 正文容器反而要更实一点(
0.56→0.76),因为里面有长文,需要稳定的对比度。
动效同理,只做两件事:
.post-card {
transition: transform 0.55s cubic-bezier(0.32, 0.72, 0, 1),
box-shadow 0.55s cubic-bezier(0.32, 0.72, 0, 1);
}
.post-card:hover {
transform: translateY(-3px);
box-shadow: 0 24px 60px -18px rgba(16, 18, 27, 0.22);
}
位移 3px,缓动函数用 iOS 的 cubic-bezier(0.32, 0.72, 0, 1)——起步快、收尾长,惯性感就出来了。位移再大一点,就会变成「网页特效」。
深色模式不是把颜色反转
这是踩得最久的一个坑。深色下白玻璃变成黑玻璃,但参数不能直接取反:
html[data-theme="dark"] .glass {
background: rgba(28, 28, 32, 0.55);
border: 1px solid rgba(255, 255, 255, 0.10);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07);
}
区别在于:深色下高光要更弱、投影要更强。因为深色背景本身不反射,玻璃边缘那道亮线一旦明显,看起来就像描了个白边。
背景的渐变也要重新调。深色下蓝色容易发灰,得把明度提上去、面积收小,让它看起来像远处的光,而不是一层雾。
一句话总结
玻璃质感 = 有内容的背景 + 带饱和度的模糊 + 一道 1px 高光 + 严格的层级克制。
前三个是 CSS,最后一个才是审美。