Skip to content

Commit 82ef0af

Browse files
fix(library): keep -webkit-backdrop-filter first so glass blur survives minification (#787)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent a5edd14 commit 82ef0af

5 files changed

Lines changed: 56 additions & 7 deletions

File tree

.changeset/glass-blur-library.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tumaet/apollon": patch
3+
---
4+
5+
Fixes the editor's floating chrome — palette, node toolbars, and zoom/undo controls — losing its frosted-glass blur in Chrome and Firefox, where it rendered as a flat translucent panel.

.changeset/glass-blur-webapp.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tumaet/webapp": patch
3+
---
4+
5+
Fixes the frosted-glass toolbars, home bar, and floating controls losing their blur in Chrome and Firefox, where they showed a flat translucent panel that flickered as content scrolled behind it.

library/lib/styles/app.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@
304304
overflow-y: auto;
305305
overscroll-behavior: contain;
306306
background: var(--apollon-chrome-glass);
307-
backdrop-filter: var(--apollon-chrome-glass-blur);
308307
-webkit-backdrop-filter: var(--apollon-chrome-glass-blur);
308+
backdrop-filter: var(--apollon-chrome-glass-blur);
309309
color: var(--apollon-chrome-text);
310310
border: 1px solid var(--apollon-chrome-border);
311311
border-radius: var(--apollon-chrome-radius-lg);
@@ -539,8 +539,8 @@
539539
.react-flow__panel,
540540
.react-flow__node-toolbar {
541541
background-color: var(--apollon-chrome-glass);
542-
backdrop-filter: var(--apollon-chrome-glass-blur);
543542
-webkit-backdrop-filter: var(--apollon-chrome-glass-blur);
543+
backdrop-filter: var(--apollon-chrome-glass-blur);
544544
border: 1px solid var(--apollon-chrome-border);
545545
box-shadow: var(--apollon-chrome-shadow-floating),
546546
var(--apollon-chrome-inset-hairline);
@@ -567,8 +567,8 @@
567567
.apollon-overlay-band,
568568
.apollon-overlay-panel {
569569
background-color: transparent;
570-
backdrop-filter: none;
571570
-webkit-backdrop-filter: none;
571+
backdrop-filter: none;
572572
border: 0;
573573
box-shadow: none;
574574
border-radius: 0;
@@ -618,8 +618,8 @@
618618
.react-flow__node-toolbar,
619619
.apollon-palette {
620620
background-color: var(--apollon-chrome-surface);
621-
backdrop-filter: none;
622621
-webkit-backdrop-filter: none;
622+
backdrop-filter: none;
623623
}
624624
}
625625

packages/ui/src/styles/components.css

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,13 @@
233233
/* Shared glass surface for every floating chrome object — header islands,
234234
palette, zoom/undo controls, minimap, and the webapp home band — so they read
235235
as one family of translucent panes. The tint floor keeps text legible over a
236-
busy diagram; the inset hairline gives crispness in dark mode. */
236+
busy diagram; the inset hairline gives crispness in dark mode.
237+
-webkit-backdrop-filter is ordered before backdrop-filter because the CSS
238+
minifier collapses an identical-value prefix pair to the last declaration. */
237239
.apollon-glass {
238240
background-color: var(--apollon-chrome-glass);
239-
backdrop-filter: var(--apollon-chrome-glass-blur);
240241
-webkit-backdrop-filter: var(--apollon-chrome-glass-blur);
242+
backdrop-filter: var(--apollon-chrome-glass-blur);
241243
border: 1px solid var(--apollon-chrome-border);
242244
box-shadow: var(--apollon-chrome-shadow-floating),
243245
var(--apollon-chrome-inset-hairline);
@@ -249,8 +251,8 @@
249251
@media (prefers-reduced-transparency: reduce) {
250252
.apollon-glass {
251253
background-color: var(--apollon-chrome-surface);
252-
backdrop-filter: none;
253254
-webkit-backdrop-filter: none;
255+
backdrop-filter: none;
254256
}
255257
}
256258

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, it, expect } from "vitest"
2+
import { readFileSync } from "node:fs"
3+
import { resolve } from "node:path"
4+
5+
// The CSS minifier collapses an identical-value vendor-prefix pair to the last
6+
// declaration, so `backdrop-filter` before `-webkit-backdrop-filter` ships as
7+
// webkit-only and the glass blur dies in Chrome/Firefox. This guards the order
8+
// in the hand-written CSS so it can't regress on a dependency bump.
9+
10+
const REPO_ROOT = resolve(__dirname, "../../..")
11+
12+
const CSS_FILES = [
13+
"packages/ui/src/styles/components.css",
14+
"library/lib/styles/app.css",
15+
]
16+
17+
// Matches the broken order: an unprefixed decl immediately followed by the
18+
// same-value -webkit- decl. `-webkit-` first, or a lone decl, is safe.
19+
const BROKEN_ORDER =
20+
/(?<![-\w])backdrop-filter:\s*([^;]+);\s*-webkit-backdrop-filter:\s*\1\s*;/g
21+
22+
describe("backdrop-filter vendor-prefix ordering", () => {
23+
for (const file of CSS_FILES) {
24+
it(`${file} lists -webkit-backdrop-filter before the standard property`, () => {
25+
const css = readFileSync(resolve(REPO_ROOT, file), "utf-8")
26+
const offenders = [...css.matchAll(BROKEN_ORDER)].map((m) =>
27+
m[0].replace(/\s+/g, " ").trim()
28+
)
29+
expect(
30+
offenders,
31+
`Put -webkit-backdrop-filter BEFORE backdrop-filter in ${file}, or ` +
32+
`lightningcss drops the standard property and the blur breaks in ` +
33+
`Chrome/Firefox.`
34+
).toEqual([])
35+
})
36+
}
37+
})

0 commit comments

Comments
 (0)