Lightning CSS 去重导致 backdrop-filter 在生产环境失效

约 4 分钟 #开发
杨秋逸
杨秋逸

现象

本地开发一切正常,铺满磨砂玻璃质感。部署到 Cloudflare Workers 之后,所有毛玻璃面板——首页的 UPageCard、CommandPalette、Drawer——全部变成纯透明,背景虚化效果完全消失。

DevTools 确认居然是 backdrop-filter: none

排查过程

首先怀疑是不是 Cloudflare Workers 环境差异,试了 Curl、Rocket Loader、各种 header——都不是。

用 Playwright 启动 Chrome 无头浏览器直接对比 Dev 和生产构建产物的计算样式:

  • Dev:backdropFilter: "blur(24px) saturate(1.35) contrast(1.05) brightness(1.04)"
  • Prod:backdropFilter: "none"

关键一步是用 Playwright 创建隔离测试——只通过 inline style 测试 Chrome 对 backdrop-filter-webkit-backdrop-filter 的支持情况:

inline style计算值
backdrop-filter: blur(1.5rem)blur(24px) saturate(1.35)
-webkit-backdrop-filter: blur(1.5rem)none

Chrome 根本不认 -webkit-backdrop-filter 那生产 CSS 里是什么情况?

看一眼生产构建的 CSS 产物:

/* 源码 */
.glass-surface {
    backdrop-filter: blur(1.5rem) saturate(1.35) contrast(1.05) brightness(1.04);
    -webkit-backdrop-filter: blur(1.5rem) saturate(1.35) contrast(1.05)
        brightness(1.04);
}

/* Lightning CSS 压缩后 */
.glass-surface {
    -webkit-backdrop-filter: blur(1.5rem) saturate(1.35) contrast(1.05)
        brightness(1.04);
}

unprefixed 的 backdrop-filter 被完全丢弃了,只留下了 Chrome 不认的 -webkit-backdrop-filter

根因

Nuxt 生产构建使用 Lightning CSS 做 CSS 压缩。Lightning CSS 在处理同时存在的 backdrop-filter-webkit-backdrop-filter 时,会做 dedup:保留后声明的那个,丢弃另一个。

源码顺序:backdrop-filter 在前 → -webkit-backdrop-filter 在后 → Lightning CSS 保留 -webkit-backdrop-filter,丢弃 backdrop-filter

但 Chrome 不识别 -webkit-backdrop-filter(它是早期的 WebKit 专有前缀,Chromium 早已转向标准属性),导致计算值为 none

对应 Lightning CSS Issue:

  • #695 — 首次报告 backdrop-filter 输出只保留 -webkit- 前缀版本
  • #785 — 报告同时使用两个前缀时 backdrop-filter 被移除,并给出了确认有效的工作思路

修复

把声明顺序颠倒——让 -webkit-backdrop-filter 在前,backdrop-filter 在后:

.glass-surface {
    -webkit-backdrop-filter: blur(1.5rem) saturate(1.35) contrast(1.05)
        brightness(1.04);
    backdrop-filter: blur(1.5rem) saturate(1.35) contrast(1.05) brightness(1.04);
}

改为把 -webkit- 放前面、unprefixed 放后面后,构建产物中 两个声明都被完整保留,实际输出如下:

.glass-surface {
    -webkit-backdrop-filter: blur(1.5rem) saturate(1.35) contrast(1.05)
        brightness(1.04);
    backdrop-filter: blur(1.5rem) saturate(1.35) contrast(1.05) brightness(1.04);
}

Chrome 忽略 -webkit- 版本,使用 unprefixed 版本,计算值恢复正常。

涉及本项目的 5 处修改(app/assets/css/main.css):.glass-surface.glass-header.glass-control.gallery-card-copy.glass-menu-item::before

总结

Lightning CSS 在做 prefix dedup 时,对 backdrop-filter 的处理存在一个已知问题——当同时存在 backdrop-filter-webkit-backdrop-filter 时,会丢弃其中一个。现代浏览器(Chrome / Edge)不认 -webkit- 前缀,导致属性完全失效。

目前的 workaround 很简单:-webkit- 声明放在 unprefixed 声明之前,确保两个版本都被保留。Chrome 使用 unprefixed 版本,Safari 使用 -webkit- 版本,互不干扰。