fix(ui): solid glass fallback when backdrop-filter is unsupported (#1817) - #2569
Conversation
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsThis is a small, low-risk CSS + class-name change. Let me verify the key semantic concern: whether the The diff shows:
The one place No crash, no security issue, no guard removal, no normal-path breakage. Committed No findings. [OPUS-REVIEWED] 97d6a98 Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
Design Review (Fable 5) — 🟡 CONCERNSAdvisory design-level review of Design-Verdict: CONCERNS Sound fallback pattern, but no reproduction on an affected environment — the query may never match where #1817 actually happens. Watch
[DESIGN-REVIEWED] 97d6a98 |
UX Review (Fable 5) — ✅ PASSAdvisory UX-level review of UX-Verdict: PASS Solid-card fallback reads cleanly in both themes and mirrors the existing reduced-transparency degradation; no new strings, flows, or controls to misread. Suggestions
[UX-REVIEWED] 97d6a98 |
) Every glass surface derives its real opacity from backdrop-filter alone: .glass-surface carries a 3-8% alpha gradient, .topbar-glass a transparent color-mix, and the notification sheet's floating cards a 55% color-mix + backdrop-blur. Where the engine does not support backdrop-filter the blur declaration is dropped at parse time and only the near-invisible tint remains -- the transparent notifications panel reported on Linux/AppImage. Add an '@supports not ((backdrop-filter) or (-webkit-backdrop-filter))' block mirroring the existing prefers-reduced-transparency fallback: solid var(--bg) for .glass-surface/.topbar-glass, solid var(--card) for the new .notif-material hook on the notification cards. Borders and shadows stay, so panels remain delimited; platforms with working backdrop-filter never match the query and keep the glass look unchanged. A feature query cannot be exercised by vitest/jsdom, so the fallback is verified by an asserting Playwright harness against the built SPA with the query guard forced on a scratch copy of dist (screenshots under temp-screenshots/glass-surface-fallback/). Closes #1817
08966be to
97d6a98
Compare
…rodotdev#1817) (kirodotdev#2569) Every glass surface derives its real opacity from backdrop-filter alone: .glass-surface carries a 3-8% alpha gradient, .topbar-glass a transparent color-mix, and the notification sheet's floating cards a 55% color-mix + backdrop-blur. Where the engine does not support backdrop-filter the blur declaration is dropped at parse time and only the near-invisible tint remains -- the transparent notifications panel reported on Linux/AppImage. Add an '@supports not ((backdrop-filter) or (-webkit-backdrop-filter))' block mirroring the existing prefers-reduced-transparency fallback: solid var(--bg) for .glass-surface/.topbar-glass, solid var(--card) for the new .notif-material hook on the notification cards. Borders and shadows stay, so panels remain delimited; platforms with working backdrop-filter never match the query and keep the glass look unchanged. A feature query cannot be exercised by vitest/jsdom, so the fallback is verified by an asserting Playwright harness against the built SPA with the query guard forced on a scratch copy of dist (screenshots under temp-screenshots/glass-surface-fallback/). Closes kirodotdev#1817
Closes #1817
Summary
On the Linux AppImage build the notifications bell panel renders see-through. Root cause: every glass surface in the dashboard derives its real opacity entirely from
backdrop-filter—.glass-surfacecarries only a 3–8% alpha gradient,.topbar-glassa transparentcolor-mix, and the notification sheet's floating cards a 55%color-mix+backdrop-blur. Where the engine does not support the property, the blur declaration is dropped at parse time and only the near-invisible tint remains.website/src/index.csshad no@supportsfallback anywhere.Change
website/src/index.css— new@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)))block (both prefixes tested — Electron/Chromium historically supported one or the other), mirroring the existingprefers-reduced-transparencyfallback so there is one consistent degradation story: solidvar(--bg)for.glass-surface/.topbar-glass, solidvar(--card)for the notification cards. Borders and shadows untouched, so panels stay visually delimited. Placed before the a11y overrides; those use!importantand later source order, so they still win when both apply.website/src/components/notifications/NotificationFeed.tsx— adds anotif-materialclass hook to the six mac-variant translucent card surfaces. Justification for going beyond the two glass classes: the reported surface is these cards (on v0.1.3 and on main the bell sheet is intentionally transparent, macOS-NC style, and every readable element is a floatingcolor-mix+backdrop-blurcard —.glass-surfacethere is only the error-boundary fallback). They fail exactly the same way, so they get exactly the same fallback. Class-name-only change, no logic..file-chipcomposes.glass-surfacein markup, so it is already covered;.glass-refract::beforeis a decorative highlight that does not depend on backdrop-filter for opacity — excluded.Under the fallback, hover/active background tints flatten (borders still convey state) — the same trade the existing
prefers-reduced-transparencyoverride already makes. Platforms with workingbackdrop-filternever match the query: zero visual change on macOS/Windows and on Linux with a compositor.Verification
A feature query cannot be exercised by vitest/jsdom, so per the issue's nature this is verified by build + asserting screenshots instead of a unit test:
website/scripts/capture-glass-surface-fallback.mjsruns the real built SPA. Desktop Chromium always parsesbackdrop-filter, so the fallback branch is proven on a scratch copy ofdistwith the query guard rewritten to a tautology — the rule body is byte-identical to what ships, only the guard is forced. Frames assert computed styles, not just pixels:01-glass-normal: unmodified dist — card bgcolor(srgb … / 0.55)(translucent, glass unchanged) ✔02-fallback-solid: forced guard, dark — card bgrgb(33, 29, 37)(opaque) ✔03-fallback-light: forced guard, light — card bgrgb(255, 255, 255)(theme-following) ✔Close-ups of the panel region: normal · fallback dark · fallback light
Local gates:
npx tsc -b✔,npx vitest run✔ (12,162 pass; two full-suite teardown flakes in unrelated apps pass in isolation),isort/flake8/mypy✔,python -m pytest40,368 pass with 65 failures that are host-environmental (this box deniesunshare(CLONE_NEWUSER), so the sandbox backend is unavailable; identical failures on clean main).Known residual
A feature query detects parse support, not runtime compositing failure. Linux GPU states where Chromium parses
backdrop-filterbut silently fails to composite it are not covered — that would need JS runtime probing and is beyond a CSS-only degradation story. This fix covers engines/builds where the property is genuinely unsupported (flag-gated or compiled out), and establishes the fallback pattern such probing could later toggle.