From d0b7381e99930eeef245eb3c059820ecd5ade04b Mon Sep 17 00:00:00 2001 From: Terencio Agozzino Date: Fri, 6 Nov 2026 21:26:18 +0100 Subject: [PATCH] fix: end the page in the footer's colour behind Safari's toolbar Past the bottom of the page, iPhone Safari showed the theme's background under the green footer. The root now has its own background: the theme's at the top, the footer's once the footer is on screen. Co-Authored-By: Claude Opus 5.5 --- src/layouts/Base.astro | 8 ++++++++ src/styles/global.css | 9 +++++++++ tests/site.spec.ts | 15 +++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro index 3d335e5..9626d1e 100644 --- a/src/layouts/Base.astro +++ b/src/layouts/Base.astro @@ -165,6 +165,14 @@ const jsonLd = { ); document.querySelectorAll('.reveal').forEach((el) => observer.observe(el)); + // Past the bottom of the page, the footer's colour rather than the theme's. + const footer = document.querySelector('footer'); + if (footer) { + new IntersectionObserver(([entry]) => + document.documentElement.classList.toggle('at-end', entry.isIntersecting), + ).observe(footer); + } + // Besides page views, GoatCounter counts what a visitor came for: a PDF // downloaded (CV, thesis), an email started, or a link followed out. declare global { diff --git a/src/styles/global.css b/src/styles/global.css index 0987824..600fc47 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -106,6 +106,15 @@ html { scroll-behavior: smooth; scroll-padding-top: 80px; + /* What a browser shows past the page's edges: behind Safari's toolbar on + iPhone, and when a scroll bounces. The theme's background at the top, the + footer's green once the footer is on screen (set in Base.astro), so the + page never ends on a band of another colour. */ + background: var(--bg); +} + +html.at-end { + background: var(--closing); } body { diff --git a/tests/site.spec.ts b/tests/site.spec.ts index 50204d5..6229ca8b 100644 --- a/tests/site.spec.ts +++ b/tests/site.spec.ts @@ -238,6 +238,21 @@ test('starts the name near the top on a phone, under a navigation that floats', await expect(page.locator('#nav')).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); }); +test("paints past the page's edges in the theme's colour, then the footer's", async ({ page }) => { + await page.goto('/'); + const html = page.locator('html'); + const background = (selector: string) => + page.locator(selector).evaluate((el) => getComputedStyle(el).backgroundColor); + + // At the top, what shows past the edge matches the page. + expect(await background('html')).toBe(await background('body')); + + // At the bottom, behind Safari's toolbar, it matches the footer. + await page.locator('footer').scrollIntoViewIfNeeded(); + await expect(html).toHaveClass(/at-end/); + await expect(html).toHaveCSS('background-color', await background('footer')); +}); + test('counts the visit, and the CV, the thesis, an email and a link out', async ({ page }) => { // A stand-in for GoatCounter's script, which records what it is given. await page.route('https://gc.zgo.at/count.js', (route) =>