🐞 fix: Update chrome tint visibility handling to prevent dark bars over page content and enhance related tests
Deploy to Dreamhost (dev) / build (push) Successful in 36s
Sync TODOs with Issues / sync_todos (push) Successful in 6s

This commit is contained in:
Keith Solomon
2026-07-12 15:13:55 -05:00
parent 2b0daaa699
commit 7267f67d99
2 changed files with 48 additions and 6 deletions
+10 -4
View File
@@ -81,11 +81,16 @@ main#maincontent {
* backgroundColor is updated at runtime by
* static/js/modules/ChromeTint.js.
*
* visibility: hidden keeps the elements invisible to the user (so
* they don't appear as dark bars over the page content) while iOS
* Safari still samples their backgroundColor. The WebKit source
* explicitly notes that visibility: hidden elements ARE sampled.
*
* The elements are kept as small as possible (12px tall) so they
* stay well within the iOS safe-area insets and don't intrude into
* the page content. They have no background by default — they only
* become opaque when the matching element (header / footer) is in
* view. pointer-events: none ensures they never intercept clicks.
* stay well within the iOS safe-area insets. They have no background
* by default — they only get a backgroundColor when the matching
* element (header / footer) is in view. pointer-events: none ensures
* they never intercept clicks even if made visible.
*
* (iOS 26 ignores <meta name="theme-color">; this technique is
* what replaced it.)
@@ -93,6 +98,7 @@ main#maincontent {
.chrome-tint {
pointer-events: none;
position: fixed;
visibility: hidden;
z-index: 9999;
}
+38 -2
View File
@@ -61,6 +61,7 @@ test.describe("chrome tint", () => {
width: Math.round(topR.width),
widthPct: Math.round((topR.width / winW) * 100),
position: topCs.position,
visibility: topCs.visibility,
},
bottom: {
bottomFromViewport: Math.round(winH - bottomR.bottom),
@@ -68,20 +69,55 @@ test.describe("chrome tint", () => {
width: Math.round(bottomR.width),
widthPct: Math.round((bottomR.width / winW) * 100),
position: bottomCs.position,
visibility: bottomCs.visibility,
},
};
});
// Top element: position fixed, top ≤ 4px, width >= 80%, height >= 12px.
// Top element: position fixed, top ≤ 4px, width >= 80%, height >= 12px,
// visibility hidden (so it never appears as a dark bar over page content).
expect(layout.top.position).toBe("fixed");
expect(layout.top.top).toBeLessThanOrEqual(4);
expect(layout.top.widthPct).toBeGreaterThanOrEqual(80);
expect(layout.top.height).toBeGreaterThanOrEqual(12);
expect(layout.top.visibility).toBe("hidden");
// Bottom element: position fixed, within 3px of viewport bottom, width >= 80%.
// Bottom element: position fixed, within 3px of viewport bottom, width >= 80%,
// visibility hidden.
expect(layout.bottom.position).toBe("fixed");
expect(layout.bottom.bottomFromViewport).toBeLessThanOrEqual(3);
expect(layout.bottom.widthPct).toBeGreaterThanOrEqual(80);
expect(layout.bottom.visibility).toBe("hidden");
});
test("fixed chrome tint elements are not visible to the user (no extra dark bars)", async ({
page,
}) => {
await page.goto(site, { waitUntil: "networkidle" });
// Wait for ChromeTint to set the background colors.
await page.waitForFunction(
() => {
const top = document.querySelector(".chrome-tint--top");
const bottom = document.querySelector(".chrome-tint--bottom");
return top && bottom &&
top.style.backgroundColor !== "" &&
bottom.style.backgroundColor === "";
},
{ timeout: 2000 },
);
// Even though the elements have background colors, they should
// be invisible to the user (visibility: hidden) so they don't
// show as dark bars over the page content.
const visibility = await page.evaluate(() => {
const top = document.querySelector(".chrome-tint--top");
const bottom = document.querySelector(".chrome-tint--bottom");
return {
top: getComputedStyle(top).visibility,
bottom: getComputedStyle(bottom).visibility,
};
});
expect(visibility.top).toBe("hidden");
expect(visibility.bottom).toBe("hidden");
});
test("viewport meta includes viewport-fit=cover", async ({ page }) => {