From 07eaf316a04dd02767d53bba730beb62828e2ab9 Mon Sep 17 00:00:00 2001 From: matt Date: Sun, 21 Sep 2025 14:37:28 +0200 Subject: [PATCH] Stabilize mobile nav padding and extend hero video --- apps/website/assets/css/voyage-layout.css | 67 ++++++++++------------- apps/website/components/AppNavbar.vue | 23 ++++++++ 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/apps/website/assets/css/voyage-layout.css b/apps/website/assets/css/voyage-layout.css index 3d95c42..5aa46e0 100644 --- a/apps/website/assets/css/voyage-layout.css +++ b/apps/website/assets/css/voyage-layout.css @@ -29,10 +29,15 @@ /* Typography */ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; --font-display: 'Playfair Display', serif; - + /* Transitions */ --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); --transition-slow: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); + + /* Safe area helpers */ + --safe-area-top: env(safe-area-inset-top, 0px); + --safe-area-bottom: env(safe-area-inset-bottom, 0px); + --initial-safe-area-top: env(safe-area-inset-top, 0px); } @@ -223,37 +228,34 @@ html { background: rgba(255, 255, 255, 0); backdrop-filter: blur(0); transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease, backdrop-filter 0.3s ease; - padding: calc(var(--space-md) + env(safe-area-inset-top, 0)) 0 var(--space-md) 0; + --nav-safe-area-top: var(--safe-area-top); + --nav-padding-top: calc(var(--space-md) + var(--nav-safe-area-top)); + --nav-padding-bottom: var(--space-md); + padding: var(--nav-padding-top) 0 var(--nav-padding-bottom) 0; +} + +@supports (top: constant(safe-area-inset-top)) { + :root { + --safe-area-top: constant(safe-area-inset-top); + --safe-area-bottom: constant(safe-area-inset-bottom); + --initial-safe-area-top: constant(safe-area-inset-top); + } } .voyage-nav.scrolled { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); - padding: calc(var(--space-sm) + env(safe-area-inset-top, 0)) 0 var(--space-sm) 0; + --nav-safe-area-top: var(--initial-safe-area-top); + --nav-padding-top: calc(var(--space-sm) + var(--nav-safe-area-top)); + --nav-padding-bottom: var(--space-sm); + padding: var(--nav-padding-top) 0 var(--nav-padding-bottom) 0; } @media (max-width: 768px) { - .voyage-nav, - .voyage-nav.scrolled { - padding: calc(var(--space-sm) + env(safe-area-inset-top, 0)) 0 var(--space-sm) 0; - } -} - -@supports (padding-top: constant(safe-area-inset-top)) { .voyage-nav { - padding: calc(var(--space-md) + constant(safe-area-inset-top)) 0 var(--space-md) 0; - } - - .voyage-nav.scrolled { - padding: calc(var(--space-sm) + constant(safe-area-inset-top)) 0 var(--space-sm) 0; - } - - @media (max-width: 768px) { - .voyage-nav, - .voyage-nav.scrolled { - padding: calc(var(--space-sm) + constant(safe-area-inset-top)) 0 var(--space-sm) 0; - } + --nav-padding-top: calc(var(--space-sm) + var(--nav-safe-area-top)); + --nav-padding-bottom: var(--space-sm); } } @@ -446,26 +448,17 @@ html { .hero-video-container { position: fixed; - left: 0; - right: 0; - /* Pull the background up into the unsafe area */ - top: calc(-1 * env(safe-area-inset-top, 0)); - height: calc(100lvh + env(safe-area-inset-top, 0)); - z-index: -1; /* Behind everything */ + inset: 0; + height: calc(100lvh + var(--safe-area-top)); + transform: translateY(calc(-1 * var(--safe-area-top))); + z-index: 0; /* Behind content but above page background */ + pointer-events: none; } /* Fallback for browsers without lvh support */ @supports not (height: 100lvh) { .hero-video-container { - height: calc(100vh + env(safe-area-inset-top, 0)); - } -} - -/* Older iOS fallback that still uses constant() */ -@supports (top: constant(safe-area-inset-top)) { - .hero-video-container { - top: calc(-1 * constant(safe-area-inset-top)); - height: calc(100vh + constant(safe-area-inset-top)); + height: calc(100vh + var(--safe-area-top)); } } diff --git a/apps/website/components/AppNavbar.vue b/apps/website/components/AppNavbar.vue index afa13f6..0804a31 100644 --- a/apps/website/components/AppNavbar.vue +++ b/apps/website/components/AppNavbar.vue @@ -57,6 +57,18 @@ const logoAlt = computed(() => isScrolled.value ? 'Harbor Smith Navy Logo' : 'Harbor Smith White Logo' ) +const setInitialSafeAreaTop = () => { + if (typeof window === 'undefined') { + return + } + + const root = document.documentElement + const styles = getComputedStyle(root) + const safeAreaTop = styles.getPropertyValue('--safe-area-top').trim() + + root.style.setProperty('--initial-safe-area-top', safeAreaTop || '0px') +} + const handleScroll = () => { isScrolled.value = window.pageYOffset > 50 } @@ -75,11 +87,22 @@ const scrollToTop = () => { } onMounted(() => { + setInitialSafeAreaTop() handleScroll() window.addEventListener('scroll', handleScroll, { passive: true }) + window.addEventListener('orientationchange', setInitialSafeAreaTop) + + if (window.visualViewport) { + window.visualViewport.addEventListener('resize', setInitialSafeAreaTop) + } }) onBeforeUnmount(() => { window.removeEventListener('scroll', handleScroll) + window.removeEventListener('orientationchange', setInitialSafeAreaTop) + + if (window.visualViewport) { + window.visualViewport.removeEventListener('resize', setInitialSafeAreaTop) + } })