一句话答案。两行代码就能得到效果:import { LiquidGlass } from 'apple-liquid-glass-webgl',
然后 new LiquidGlass('.navbar')。元素的内容、布局和事件保持不变,玻璃绘制在子元素之后,形状和圆角取自元素的 CSS
border-radius。支持 React、Next.js、Vue、Svelte 和原生 HTML;没有 WebGL2 时自动回退到
backdrop-filter。
为什么在 Safari 和 Firefox 上也不会退化。大多数液态玻璃库用
backdrop-filter: url(#filter) 驱动 SVG 置换贴图,而只有 Chromium 支持这种写法:Safari 和 Firefox
会接受这个属性、却静默丢掉 SVG 部分,最后只剩一层平铺的模糊。这个库完全不用它 ——
它把元素背后的页面重绘成纹理,再在 WebGL2 片元着色器里弯折这张纹理,而 WebGL2 在 Chrome、Edge、Firefox 和
Safari 15+ 上都已支持。而且你不会失去 DOM:被重绘的只有背景,元素自己的子节点原封不动,
文字仍然是真正的文字 —— 可以选中、可以翻译、可以被读屏软件读取。这正是大多数人选择 WebGL 方案时不得不放弃的东西。
它是什么
apple-liquid-glass-webgl 是一个用 WebGL2 在网页上渲染苹果液态玻璃材质的开源(MIT)JavaScript 包。 浏览器不允许 WebGL 读取页面像素,所以这个库自己把玻璃背后的内容重绘成一张纹理,再用有向距离场(SDF)折射着色器处理它。 得到的表面会弯折背后的页面、在边缘收拢场景、让颜色通道轻微分离,并带有边缘光、镜面高光和轮廓细线 —— 这是苹果材质真实的光学行为,而不是一个模糊的矩形。
它可以用在普通 DOM 元素(导航栏、卡片、提示条、侧边栏)上,可以把一组元素画在同一张画布上, 也可以用在你自己的 canvas、游戏或 WebGL 场景中。零运行时依赖,原生 ES 模块,附带 TypeScript 声明,无需构建配置。
三种方案怎么选:CSS、SVG 置换贴图,还是 WebGL?
网页上做液态玻璃只有三条路,各自的短板不同。纯 CSS backdrop-filter 只能模糊和着色,不能弯折光线。
用 backdrop-filter: url(#filter) 驱动 SVG 置换贴图确实能折射,但只在 Chromium 上有效 ——
Safari 和 Firefox 会丢掉滤镜,只剩一层模糊。WebGL 着色器则在任何支持 WebGL2 的浏览器上都能折射,
代价是要自己重绘背景。本库属于第三种。
CSS backdrop-filter | SVG 置换贴图 | apple-liquid-glass-webgl | |
|---|---|---|---|
| 模糊与着色 | 支持 | 支持 | 支持(frost、tint、tintTone) |
| 玻璃体内折射 | 不支持 | 支持 | 支持(refraction) |
| Safari / Firefox 上的折射 | 不适用 | 不支持,退化为模糊 | 支持,两者都有 WebGL2 |
| 边缘捕捉:边界处场景被压缩 | 不支持 | 受 ±127px 位移范围限制 | 支持(edgeReach、edgeWidth) |
| 色散 | 不支持 | 按通道近似 | 支持(dispersion) |
| 边缘光、背景反射、镜面高光 | 只能用渐变模拟 | 只能用渐变模拟 | 由真实背景计算得出 |
| 控件按压形变 | 不支持 | 不支持 | 支持(pressure) |
| 内容保持原生 DOM | 是 | 是 | 是,玻璃绘制在子元素之后 |
| 开销 | 合成器 | 每帧滤镜链 | 一个 WebGL2 上下文,仅在变化时重绘 |
三者并不冲突:backdrop-filter 就是本库内置的回退方案,没有 WebGL2 的环境会退化成常规毛玻璃。
人们对 WebGL 玻璃方案最常见的顾虑 —— 会牺牲语义化 HTML 和无障碍 —— 在这里不成立:被画进 canvas 的只有背景, 元素自己的子节点从不参与重绘,所以文字可选中、可被读屏软件读取,链接可聚焦,事件处理也照常工作。
快速开始
import { LiquidGlass } from 'apple-liquid-glass-webgl';
new LiquidGlass('.navbar');
集成到此为止。玻璃上要放文字时需要一点“体积感”,tint 的曲线很缓,可读的取值大约在 0.5–0.8:
new LiquidGlass('.panel', { frost: 0.45, tint: 0.5, tintTone: 'light' }); // 深色文字
new LiquidGlass('.toast', { frost: 0.3, tint: 0.7, tintTone: 'dark' }); // 白色文字
卡片网格要共用一张画布,而不是每张卡片一个上下文:
new LiquidGlass('.card-grid', { targets: '.card', frost: 0.3, tint: 0.2 });
const glass = new LiquidGlass('.card', options);
await glass.ready; // 首帧绘制完成、图片加载完成
glass.update({ tint: 0.4 }); // 合并选项
glass.refresh(); // 重新读取选择器并重绘
glass.destroy(); // 还原元素,释放 WebGL 上下文
玻璃背后是什么
默认情况下你不需要提供任何背景。backdrop: 'auto' 会按 CSS 绘制顺序(含 z-index)
重绘元素下方的页面:背景、边框、<img>、<video>、<canvas> 和文字。
滚动到固定导航栏下方的标题,会出现在玻璃里,并且和页面上的位置严格对齐。
要折射别的东西,就告诉它背后是什么:元素选择器('#hero-video')、图片地址('/wallpaper.jpg')、
类似 object-fit 的适配对象、自定义绘制函数 (ctx, region) => {},或它们组成的数组(自下而上)。
所有内容都按页面坐标注册。跨域图片需要 CORS 响应头。auto 不会重绘
::before/::after、阴影、CSS 滤镜、SVG 和表单控件 —— 这些用绘制函数补上。
框架用法(React / Vue / Svelte)
// React:在 useEffect 中创建,清理时 destroy(StrictMode 双次挂载下安全)
function Glass({ options, ...props }) {
const ref = useRef(null);
useEffect(() => {
const glass = new LiquidGlass(ref.current, options);
return () => glass.destroy();
}, []);
return <div ref={ref} {...props} />;
}
// Vue
onMounted(() => { glass = new LiquidGlass(el.value, { tint: 0.2 }); });
onBeforeUnmount(() => glass.destroy());
自带控件:导航栏与开关
import { LiquidGlassNavbar, LiquidGlassSwitch } from 'apple-liquid-glass-webgl';
const nav = new LiquidGlassNavbar('#nav', {
items: [{ value: 'home', label: '首页' }, { value: 'work', label: '作品' }],
value: 'home',
onChange: (value) => router.push(value),
});
const toggle = new LiquidGlassSwitch('#dark-mode', {
checked: false,
onChange: (checked) => document.documentElement.classList.toggle('dark', checked),
});
按住时旋钮会原地绽放,拖过中点即切换状态;方向键、Home/End 和空格都可用,带完整 ARIA。尺寸由你的 CSS 决定。
兼容性、性能与限制
- 兼容性:任何支持 WebGL2 的浏览器 —— Chrome、Edge、Firefox、Safari 15 及以上,桌面与移动端均可;
其余环境自动使用 CSS
backdrop-filter回退。 - 上下文数量:每页约 16 个 WebGL 上下文。玻璃元素或开关各占一个,导航栏占两个;用
targets合并。 - 重绘:没有变化就不重绘。滚动、缩放、字体加载、DOM/类名/样式变化、CSS 过渡结束都会自动捕捉。
- 无障碍:默认尊重
prefers-reduced-transparency。 - 已知限制:
auto不处理伪元素、阴影、滤镜、SVG 和表单控件;旋转文字按未旋转绘制; 跟随缩放与平移变换,但不跟随旋转;跨域图片需要 CORS。
常见问题
网页上怎么做出苹果的液态玻璃效果?
从 npm 安装 apple-liquid-glass-webgl,然后 new LiquidGlass('.navbar')。
元素内容、布局和事件都不受影响,形状取自元素的 CSS border-radius。不需要壁纸、不需要 canvas、不需要构建步骤。
和 CSS 毛玻璃(backdrop-filter)有什么不同?
backdrop-filter 只能模糊和着色;液态玻璃还会折射、在边缘收拢场景、让颜色轻微分离。
这个库把页面重绘后交给 WebGL2 的 SDF 折射着色器,因此有边缘捕捉、色散、边缘光、背景反射、镜面高光和轮廓细线。
支持 React / Vue / Svelte 吗?
支持,且不依赖框架:元素存在后创建,卸载时 destroy()。React 的 StrictMode 双次挂载下安全,SSR 时导入也安全。
必须自己提供背景图吗?
不需要。默认 backdrop: 'auto' 折射的就是真实页面,并按页面坐标持续对齐。
Safari 和 Firefox 上能用吗?折射会不会失效?
能用,且折射完整保留。这正是其他方案最常翻车的地方:大多数液态玻璃库依赖
backdrop-filter: url(#filter),而只有 Chromium 支持它,Safari 和 Firefox 会丢掉滤镜只留下模糊。
本库在 WebGL2 着色器里弯折背景,而 WebGL2 在 Chrome、Edge、Firefox 和 Safari 15+ 上均已支持(桌面端和移动端)。
会不会像其他 WebGL 方案那样丢失 DOM 和无障碍?
不会。只有背景被重绘进 canvas,元素自己的子节点不动,因此文字仍可选中、可翻译、可被读屏软件读取,
事件、布局和 CSS 都不受影响。玻璃位于子元素之后(z-index: -1)。
可以在 Next.js 里用吗?不用 React 行不行?
都可以。它是一个与框架无关的类,原生 HTML 加 <script type="module"> 就够了。
Next.js App Router 里,在创建实例的组件文件顶部加 'use client' 即可,不需要任何 React 封装包。
不支持 WebGL2 怎么办?
自动回退到 CSS backdrop-filter;元素上的 data-liquid-glass 属性会标明当前是
webgl 还是 fallback。
是免费开源的吗?
是,MIT 许可证,零运行时依赖,原生 ES 模块 + TypeScript 声明。源码见 GitHub,包发布在 npm。
包信息
| 包名 | apple-liquid-glass-webgl(npm) |
|---|---|
| 版本 | 2.6.0 |
| 许可证 | MIT |
| 运行时依赖 | 无 |
| 主要导出 | LiquidGlass、LiquidGlassWebGL、LiquidGlassNavbar、LiquidGlassSwitch、getDefaultMaterial |
| 仓库 | github.com/Oliverrr2424/webgl-apple-liquid-glass |
| 演练场 | oliverrr2424.github.io/webgl-apple-liquid-glass |
| 机器可读摘要 | /llms.txt、/llms-full.txt |