Fix Page transitions by using a hacky FOUC trick
Seems to work though!
This commit is contained in:
@@ -15,5 +15,9 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="housesof">%svelte.body%</div>
|
<div id="housesof">%svelte.body%</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.body.style.opacity = '0'
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -5,19 +5,32 @@
|
|||||||
export let tag: string
|
export let tag: string
|
||||||
export let label: string = undefined
|
export let label: string = undefined
|
||||||
export let parallax: number = undefined
|
export let parallax: number = undefined
|
||||||
export let offset: number = 0
|
export let offsetStart: number = undefined
|
||||||
|
export let offsetEnd: number = undefined
|
||||||
export let animate: boolean = true
|
export let animate: boolean = true
|
||||||
|
|
||||||
let scrollY: number
|
let scrollY: number
|
||||||
|
let innerWidth: number
|
||||||
|
let innerHeight: number
|
||||||
let titleEl: HTMLElement
|
let titleEl: HTMLElement
|
||||||
|
let isLarger: boolean
|
||||||
|
|
||||||
$: if (titleEl) {
|
// Define default values
|
||||||
const start = titleEl.offsetTop + offset
|
$: if (titleEl && !offsetStart && !offsetEnd) {
|
||||||
const end = titleEl.offsetTop + (titleEl.offsetHeight + offset) * 0.9
|
offsetStart = titleEl.offsetTop - innerHeight * 0.75
|
||||||
parallax = map(scrollY, start, end, 0, 1, true)
|
offsetEnd = titleEl.offsetTop + innerHeight * 0.25
|
||||||
}
|
}
|
||||||
|
|
||||||
const classes = [
|
// Check if title is larger than viewport to translate it
|
||||||
|
$: isLarger = titleEl && titleEl.offsetWidth >= innerWidth
|
||||||
|
|
||||||
|
// Calculate the parallax value
|
||||||
|
$: if (titleEl) {
|
||||||
|
const toTranslate = 100 - innerWidth / titleEl.offsetWidth * 100
|
||||||
|
parallax = isLarger ? map(scrollY, offsetStart, offsetEnd, 0, -toTranslate, true) : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
$: classes = [
|
||||||
'scrolling-title',
|
'scrolling-title',
|
||||||
'title-huge',
|
'title-huge',
|
||||||
$$props.class
|
$$props.class
|
||||||
@@ -38,20 +51,31 @@
|
|||||||
} : {}
|
} : {}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window bind:scrollY />
|
<svelte:window
|
||||||
|
bind:scrollY
|
||||||
|
bind:innerWidth bind:innerHeight
|
||||||
|
/>
|
||||||
|
|
||||||
{#if tag === 'h1'}
|
{#if tag === 'h1'}
|
||||||
<h1 bind:this={titleEl}
|
<h1 bind:this={titleEl}
|
||||||
class={classes} aria-label={label}
|
class={classes} aria-label={label}
|
||||||
style="--parallax-x: {parallax};"
|
style="--parallax-x: {parallax}%;"
|
||||||
use:reveal={revealOptions}
|
use:reveal={revealOptions}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</h1>
|
</h1>
|
||||||
|
{:else if tag === 'h2'}
|
||||||
|
<h2 bind:this={titleEl}
|
||||||
|
class={classes} aria-label={label}
|
||||||
|
style="--parallax-x: {parallax}%;"
|
||||||
|
use:reveal={revealOptions}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</h2>
|
||||||
{:else if tag === 'p'}
|
{:else if tag === 'p'}
|
||||||
<p bind:this={titleEl}
|
<p bind:this={titleEl}
|
||||||
class={classes} aria-label={label}
|
class={classes} aria-label={label}
|
||||||
style="--parallax-x: {parallax};"
|
style="--parallax-x: {parallax}%;"
|
||||||
use:reveal={revealOptions}
|
use:reveal={revealOptions}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { browser } from '$app/env'
|
|
||||||
import { page } from '$app/stores'
|
import { page } from '$app/stores'
|
||||||
import { getContext, onMount } from 'svelte'
|
import { getContext, onMount } from 'svelte'
|
||||||
import anime from 'animejs'
|
import anime from 'animejs'
|
||||||
import type { AnimeTimelineInstance } from 'animejs'
|
import type { AnimeTimelineInstance } from 'animejs'
|
||||||
|
import { DELAY } from '$utils/contants'
|
||||||
|
import { sleep } from '$utils/functions'
|
||||||
// Components
|
// Components
|
||||||
import Metas from '$components/Metas.svelte'
|
import Metas from '$components/Metas.svelte'
|
||||||
import PageTransition from '$components/PageTransition.svelte'
|
import PageTransition from '$components/PageTransition.svelte'
|
||||||
@@ -31,9 +32,12 @@
|
|||||||
*/
|
*/
|
||||||
let timeline: AnimeTimelineInstance
|
let timeline: AnimeTimelineInstance
|
||||||
|
|
||||||
if (browser) {
|
const transition = async () => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => timeline.play())
|
||||||
// Setup animations
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
timeline = anime.timeline({
|
timeline = anime.timeline({
|
||||||
duration: 1600,
|
duration: 1600,
|
||||||
easing: 'easeOutQuart',
|
easing: 'easeOutQuart',
|
||||||
@@ -41,39 +45,26 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Reveal text
|
// Reveal text
|
||||||
anime.set('.homepage__headline', {
|
|
||||||
translateY: 16,
|
|
||||||
opacity: 0,
|
|
||||||
})
|
|
||||||
timeline.add({
|
timeline.add({
|
||||||
targets: '.homepage__headline',
|
targets: '.homepage__headline',
|
||||||
translateY: 0,
|
translateY: [16, 0],
|
||||||
opacity: 1,
|
opacity: [0, 1],
|
||||||
}, 900)
|
}, 900)
|
||||||
|
|
||||||
// Animate collage photos
|
// Animate collage photos
|
||||||
anime.set('.homepage__collage .photo-card', {
|
|
||||||
opacity: 0,
|
|
||||||
translateY: '33.33%',
|
|
||||||
rotate: -4,
|
|
||||||
})
|
|
||||||
timeline.add({
|
timeline.add({
|
||||||
targets: '.homepage__collage .photo-card',
|
targets: '.homepage__collage .photo-card',
|
||||||
translateY: 0,
|
translateY: ['33.33%', 0],
|
||||||
rotate (item: HTMLElement) {
|
rotate (item: HTMLElement) {
|
||||||
return getComputedStyle(item).getPropertyValue('--rotation')
|
return [-4, getComputedStyle(item).getPropertyValue('--rotation')]
|
||||||
},
|
},
|
||||||
opacity: 1,
|
opacity: [0, 1],
|
||||||
duration: 1200,
|
duration: 1200,
|
||||||
delay: anime.stagger(75),
|
delay: anime.stagger(75),
|
||||||
}, 0)
|
}, 0)
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
await sleep(DELAY.PAGE_LOADING)
|
||||||
requestAnimationFrame(() => {
|
await transition()
|
||||||
timeline.play()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -91,7 +82,8 @@
|
|||||||
tag="h1"
|
tag="h1"
|
||||||
class="homepage__title--houses"
|
class="homepage__title--houses"
|
||||||
label="Houses of the World"
|
label="Houses of the World"
|
||||||
offsetTop={100}
|
offsetStart={-300}
|
||||||
|
offsetEnd={400}
|
||||||
>
|
>
|
||||||
<SplitText text="Houses" mode="chars" />
|
<SplitText text="Houses" mode="chars" />
|
||||||
</ScrollingTitle>
|
</ScrollingTitle>
|
||||||
@@ -150,11 +142,7 @@
|
|||||||
<section class="homepage__locations">
|
<section class="homepage__locations">
|
||||||
<InteractiveGlobe />
|
<InteractiveGlobe />
|
||||||
|
|
||||||
<ScrollingTitle
|
<ScrollingTitle tag="p" class="homepage__title--world mask">
|
||||||
tag="p"
|
|
||||||
class="homepage__title--world mask"
|
|
||||||
offset={-1 * innerHeight / 2}
|
|
||||||
>
|
|
||||||
<SplitText text="World" mode="chars" />
|
<SplitText text="World" mode="chars" />
|
||||||
</ScrollingTitle>
|
</ScrollingTitle>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.scrolling-title {
|
.scrolling-title {
|
||||||
transform: translate3d(calc(-1px * var(--parallax-x) * 100), 0, 0);
|
transform: translate3d(var(--parallax-x), 0, 0);
|
||||||
transition: transform 1.2s var(--ease-quart);
|
transition: transform 1.2s var(--ease-quart);
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,14 @@ export const capitalizeFirstLetter = (string: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a delay
|
||||||
|
*/
|
||||||
|
export function sleep (milliseconds: number) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, milliseconds))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Linear Interpolation
|
* Linear Interpolation
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user