Touch devices blur the live backdrop instead of the baked layer
Mobile engines repaint background-attachment: fixed late (iOS treats it as scroll), so the baked glass showed a stale crop of the wallpaper until a tap forced a repaint - "some of the UI looks bugged until I click it". On touch devices (max-width 639px or pointer: coarse) the bake is dropped for a real backdrop-filter over the live scene, so the bubbles blur through the glass as they pass and the position is correct by construction. Hand-rolled frost fills keep their own tints there; desktop keeps the baked layer (measured cheaper and verified correct). Pinned with a touch-context check in the mobile suite (124 checks). Contrast 0 findings, axe clean, chat 101/101, regression 44/44, i18n 13/13, native 33/33. Version 0.3.8, SW -> freezmo-v67.
This commit is contained in:
parent
4ba80a9bf2
commit
b315e2a1aa
6 changed files with 84 additions and 4 deletions
|
|
@ -1411,6 +1411,15 @@ Things I chose while building, with the reasoning:
|
||||||
pre-blurred wallpaper — the scene is clearly visible through the glass, and the
|
pre-blurred wallpaper — the scene is clearly visible through the glass, and the
|
||||||
pixel-contrast scan still passes.
|
pixel-contrast scan still passes.
|
||||||
|
|
||||||
|
73. **Touch devices blur the live backdrop; desktop keeps the bake.** Mobile engines repaint
|
||||||
|
`background-attachment: fixed` late (and iOS treats it as scroll), so the baked glass showed a
|
||||||
|
stale crop of the wallpaper until a tap forced a repaint — "some of the UI looks bugged until I
|
||||||
|
click it". On touch devices (`max-width: 639px` or `pointer: coarse`) the bake is dropped for a
|
||||||
|
real `backdrop-filter` over the live scene (what the floating chrome always did) — the bubbles
|
||||||
|
now blur *through* the glass as they pass, and the position is correct by construction. The
|
||||||
|
hand-rolled frost fills keep their own tints there; desktop keeps the baked layer (measured
|
||||||
|
cheaper there and verified correct). Pinned in `tests/mobile-test.mjs` with a touch context.
|
||||||
|
|
||||||
72. **More, shinier bubbles.** Aero's rising bubbles went from ten to eighteen (the extra eight
|
72. **More, shinier bubbles.** Aero's rising bubbles went from ten to eighteen (the extra eight
|
||||||
interleaved between the others, 18px to 96px, 10-23s runs) with a tighter specular hotspot, a
|
interleaved between the others, 18px to 96px, 10-23s runs) with a tighter specular hotspot, a
|
||||||
second reflected-light glint low on the sphere, a 1px glass edge and a brighter inner rim on
|
second reflected-light glint low on the sphere, a 1px glass edge and a brighter inner rim on
|
||||||
|
|
|
||||||
|
|
@ -597,6 +597,57 @@
|
||||||
background-repeat: no-repeat, no-repeat;
|
background-repeat: no-repeat, no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Touch devices: the baked backdrop is `background-attachment: fixed`, which
|
||||||
|
mobile engines repaint late (and iOS treats as scroll) — panes showed a
|
||||||
|
stale crop of the wallpaper until a tap forced a repaint ("some UI looks
|
||||||
|
bugged until I click it"). Touch hardware has the GPU budget for the honest
|
||||||
|
version instead: a real backdrop blur over the live scene, so the bubbles
|
||||||
|
blur through the glass as they pass. Desktop keeps the bake (measured
|
||||||
|
cheaper there, and verified correct). */
|
||||||
|
@media (max-width: 639px), (pointer: coarse) {
|
||||||
|
.aero .card,
|
||||||
|
.aero .glass-solid,
|
||||||
|
.aero .sidebar-surface,
|
||||||
|
.aero .gate-card,
|
||||||
|
.aero .list-group,
|
||||||
|
.aero .nav-action,
|
||||||
|
.aero .nav-row[aria-current="page"],
|
||||||
|
.aero .nav-row[data-active="true"],
|
||||||
|
.aero .glass-chip,
|
||||||
|
.aero .glass-pill,
|
||||||
|
.aero .btn-secondary,
|
||||||
|
.aero .btn-primary,
|
||||||
|
.aero .grad-ice,
|
||||||
|
.aero .segmented,
|
||||||
|
.aero .segmented > button[aria-pressed="true"],
|
||||||
|
.aero .segmented > a[aria-current="page"],
|
||||||
|
.aero .chat-bubble,
|
||||||
|
.aero .chat-answer {
|
||||||
|
background-image: none;
|
||||||
|
@apply backdrop-blur-md backdrop-saturate-[1.4];
|
||||||
|
}
|
||||||
|
.aero .chat-bubble,
|
||||||
|
.aero .chat-answer {
|
||||||
|
background-color: rgb(255 255 255 / 0.55);
|
||||||
|
}
|
||||||
|
.aero .tabbar {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
/* The hand-rolled frost fills drop the bake too and keep their own tints. */
|
||||||
|
.aero [class*="bg-white/35"],
|
||||||
|
.aero [class*="bg-white/40"],
|
||||||
|
.aero [class*="bg-white/45"],
|
||||||
|
.aero [class*="bg-white/50"],
|
||||||
|
.aero [class*="bg-white/55"],
|
||||||
|
.aero [class*="bg-white/60"],
|
||||||
|
.aero [class*="bg-white/70"],
|
||||||
|
.aero [class*="bg-[var(--surface)]"],
|
||||||
|
.aero [class*="bg-[var(--surface-strong)]"],
|
||||||
|
.aero [class*="bg-frost-50"] {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Inside a sheet or dialog the backdrop is not the raw scene — a scrim and a
|
/* Inside a sheet or dialog the backdrop is not the raw scene — a scrim and a
|
||||||
more opaque sheet glass sit in between — so the viewport-aligned frosted
|
more opaque sheet glass sit in between — so the viewport-aligned frosted
|
||||||
layer would not match what is actually behind the element (it showed the
|
layer would not match what is actually behind the element (it showed the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "freezmo",
|
"name": "freezmo",
|
||||||
"version": "0.3.7",
|
"version": "0.3.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
* Bumping CACHE_VERSION is how a new deploy invalidates old assets.
|
* Bumping CACHE_VERSION is how a new deploy invalidates old assets.
|
||||||
*/
|
*/
|
||||||
const CACHE_VERSION = "freezmo-v66";
|
const CACHE_VERSION = "freezmo-v67";
|
||||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||||
const ASSET_CACHE = `${CACHE_VERSION}-assets`;
|
const ASSET_CACHE = `${CACHE_VERSION}-assets`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,8 +121,8 @@ export async function seed(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function makePage(browser, { width = 390, height = 844, deviceScaleFactor = 2, reducedMotion, colorScheme } = {}) {
|
export async function makePage(browser, { width = 390, height = 844, deviceScaleFactor = 2, reducedMotion, colorScheme, isMobile, hasTouch } = {}) {
|
||||||
const context = await browser.newContext({ viewport: { width, height }, deviceScaleFactor, reducedMotion, colorScheme });
|
const context = await browser.newContext({ viewport: { width, height }, deviceScaleFactor, reducedMotion, colorScheme, isMobile, hasTouch });
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
return { context, page };
|
return { context, page };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,26 @@ const AXE = axeSource();
|
||||||
await context.close();
|
await context.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 6d. touch devices blur the real backdrop (the baked layer mispaints) - */
|
||||||
|
{
|
||||||
|
const { context, page } = await makePage(browser, { width: 390, height: 844, isMobile: true, hasTouch: true });
|
||||||
|
await seed(page, { decks: [DECK], theme: "aero" });
|
||||||
|
await page.goto(BASE, { waitUntil: "networkidle" });
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
const glass = await page.evaluate(() => {
|
||||||
|
const coarsish = matchMedia("(pointer: coarse)").matches || matchMedia("(max-width: 639px)").matches;
|
||||||
|
const el = document.querySelector(".segmented");
|
||||||
|
const cs = getComputedStyle(el);
|
||||||
|
return { coarsish, backdrop: cs.backdropFilter, image: cs.backgroundImage };
|
||||||
|
});
|
||||||
|
check(
|
||||||
|
"theme: touch glass blurs the live backdrop (no baked layer)",
|
||||||
|
glass.coarsish && glass.backdrop.includes("blur") && glass.image === "none",
|
||||||
|
JSON.stringify(glass),
|
||||||
|
);
|
||||||
|
await context.close();
|
||||||
|
}
|
||||||
|
|
||||||
/* 6c. a dark OS preference must not leak the dark palette into Aero ------ */
|
/* 6c. a dark OS preference must not leak the dark palette into Aero ------ */
|
||||||
{
|
{
|
||||||
const { context, page } = await makePage(browser, { width: 390, height: 844, colorScheme: "dark" });
|
const { context, page } = await makePage(browser, { width: 390, height: 844, colorScheme: "dark" });
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue