fix: implement Vue 3 Teleport to bypass DOM containment for iOS video extension
All checks were successful
build-website / build (push) Successful in 1m49s
All checks were successful
build-website / build (push) Successful in 1m49s
- Wrapped Teleport in ClientOnly to avoid SSR/hydration issues - Replaced env() with hardcoded -59px for Dynamic Island (Safari bug workaround) - Added !important flags to ensure styles aren't overridden - Set overflow: visible on hero-voyage container - Used z-index: 0 to ensure video stays behind content This addresses the Nuxt SSG + Teleport incompatibility and iOS Safari's env() bug 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="hero-voyage" id="heroSection">
|
<section class="hero-voyage" id="heroSection">
|
||||||
<!-- Hero video background teleported to body for proper safe area extension -->
|
<!-- Hero video background teleported to body for proper safe area extension -->
|
||||||
|
<!-- Using ClientOnly to avoid SSR/hydration issues with Teleport -->
|
||||||
|
<ClientOnly>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div ref="videoContainer" class="hero-video-container hero-video-teleported">
|
<div ref="videoContainer" class="hero-video-container hero-video-teleported">
|
||||||
<!-- White overlay that fades out when video is ready -->
|
<!-- White overlay that fades out when video is ready -->
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
<div class="hero-overlay gradient-depth" />
|
<div class="hero-overlay gradient-depth" />
|
||||||
</div>
|
</div>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
</ClientOnly>
|
||||||
|
|
||||||
<div class="hero-content" :class="{ 'is-ready': videoLoaded }">
|
<div class="hero-content" :class="{ 'is-ready': videoLoaded }">
|
||||||
<div class="hero-main">
|
<div class="hero-main">
|
||||||
@@ -174,50 +177,36 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* Hero video container - Safari-compatible safe area implementation */
|
/* Hero video container - Hardcoded safe area implementation for iOS */
|
||||||
.hero-video-container {
|
.hero-video-container {
|
||||||
position: fixed;
|
position: fixed !important;
|
||||||
left: 0;
|
left: 0 !important;
|
||||||
right: 0;
|
right: 0 !important;
|
||||||
width: 100vw;
|
width: 100vw !important;
|
||||||
/* Default fallback for devices without notch */
|
/* Hardcoded for iPhone 14/15 Pro Dynamic Island */
|
||||||
top: 0;
|
/* Using negative value to extend into safe area */
|
||||||
height: 100vh;
|
top: -59px !important;
|
||||||
z-index: 1;
|
height: calc(100vh + 59px) !important;
|
||||||
pointer-events: none;
|
z-index: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Teleported video container - positioned at body level to bypass DOM containment */
|
/* Teleported video container - ensure it stays at body level */
|
||||||
.hero-video-teleported {
|
.hero-video-teleported {
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
z-index: 1 !important;
|
z-index: 0 !important;
|
||||||
|
/* Force the video to extend beyond safe area boundaries */
|
||||||
|
top: -59px !important;
|
||||||
|
height: calc(100vh + 59px) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use @supports with max() as recommended by Apple for safe area */
|
/* Fallback for older iPhones with smaller notch */
|
||||||
@supports(padding: max(0px)) {
|
@media screen and (max-height: 812px) {
|
||||||
.hero-video-container {
|
.hero-video-container,
|
||||||
/* Use max() to provide fallback when env() returns 0 (Safari bug) */
|
.hero-video-teleported {
|
||||||
top: calc(-1 * max(env(safe-area-inset-top), 20px));
|
top: -44px !important;
|
||||||
height: calc(100vh + max(env(safe-area-inset-top), 20px));
|
height: calc(100vh + 44px) !important;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* iOS-specific fallback using -webkit-touch-callout detection */
|
|
||||||
@supports (-webkit-touch-callout: none) {
|
|
||||||
.hero-video-container {
|
|
||||||
/* Hardcoded fallback for iPhone 14/15 Pro Dynamic Island (59px) */
|
|
||||||
/* and iPhone X-13 notch (44px) - uses larger value for safety */
|
|
||||||
top: -59px;
|
|
||||||
height: calc(100vh + 59px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try env() with both modern and legacy syntax */
|
|
||||||
@supports(padding: max(0px)) {
|
|
||||||
.hero-video-container {
|
|
||||||
top: calc(-1 * max(constant(safe-area-inset-top), env(safe-area-inset-top), 59px));
|
|
||||||
height: calc(100vh + max(constant(safe-area-inset-top), env(safe-area-inset-top), 59px));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,6 +267,8 @@ onMounted(() => {
|
|||||||
max-width: 100vw !important;
|
max-width: 100vw !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
/* Explicitly allow overflow to ensure video can extend */
|
||||||
|
overflow: visible !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-main {
|
.hero-main {
|
||||||
|
|||||||
Reference in New Issue
Block a user