From ae6f23ff92d2933f4cbd92cb2c1d52d37ff793b9 Mon Sep 17 00:00:00 2001 From: Terencio Agozzino Date: Fri, 6 Nov 2026 21:05:48 +0100 Subject: [PATCH] fix(nav): float the empty navigation over the hero on phones On phones and tablets the navigation is empty at the top of the page, yet it pushed the hero down by its 60px, on top of the hero's own margin. It now floats over the hero, transparent, until the page scrolls. Co-Authored-By: Claude Opus 5.5 --- src/components/Nav.astro | 17 +++++++++++++++++ tests/site.spec.ts | 16 ++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/components/Nav.astro b/src/components/Nav.astro index 728b51c..aa82f69 100644 --- a/src/components/Nav.astro +++ b/src/components/Nav.astro @@ -124,6 +124,23 @@ const links = [ height: 60px; } + /* At the top of the page the navigation is empty here: no links, and the + name and the button are still in the hero. Rather than push the hero + down by its height, it floats over it, transparent, until the page + scrolls. Without JavaScript it shows both, so it keeps its place. */ + :global(.js) nav { + margin-bottom: -60px; + transition: + border-color 0.3s, + background 0.3s; + } + + :global(.js) nav:not(.scrolled) { + background: transparent; + backdrop-filter: none; + -webkit-backdrop-filter: none; + } + .logo { font-size: 15px; } diff --git a/tests/site.spec.ts b/tests/site.spec.ts index 45cf8a4..50204d5 100644 --- a/tests/site.spec.ts +++ b/tests/site.spec.ts @@ -222,6 +222,22 @@ test('shows the name and the button in the navigation only once scrolled past', await expect(button).toBeVisible(); }); +test('starts the name near the top on a phone, under a navigation that floats', async ({ + page, +}) => { + await page.setViewportSize({ width: 390, height: 844 }); + // Measured where the name rests, not while it fades in. + await page.emulateMedia({ reducedMotion: 'reduce' }); + await page.goto('/'); + // The empty navigation no longer pushes the hero down: only its own margin. + const top = await page.locator('#top h1').evaluate((h1) => h1.getBoundingClientRect().top); + expect(top).toBeLessThanOrEqual(48); + + // Once scrolled, it has its background again, over the content. + await page.locator('#experience').scrollIntoViewIfNeeded(); + await expect(page.locator('#nav')).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); +}); + 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) =>