How to do page transitions with svelte/sapper
Let me just start of by saying I don't know if this is the most effective way to do it. This is the way I solved it and it works great for me.
I first made my own custom variation of the 'fade' transition and put it in 'components/pageFade.js'
import { sineOut } from "svelte/easing";
let duration = 250;
let delay = duration;
let delayZero = 0;
export const fadeIn = _ => ({
duration,
delay,
easing: sineOut,
css: t => `opacity: ${t}`
});
export const fadeOut = _ => ({
duration,
delay: delayZero,
easing: sineOut,
css: t => `opacity: ${t}`
});
- The delayZero variable is there because for some reason it won't take '0' directly and will break.
- The duration variable is the length of the fade in milliseconds
Then for all files I wanted to have this transition on I did the following:
<script>
import { fadeIn, fadeOut } from "../components/pageFade";
// All your other JS goes here
</script>
<style>
/* Styles go here */
</style>
<main in:fadeIn out:fadeOut>
<!-- All the normal HTML goes here -->
</main>
I would then use that as a template on almost every single one of the pages, which seems like a lot but it's not too bad.
Hope it helps and let me know if you have any other questions!
Max
FYI @max-larsson, from your code, fadeIn
is defined as a function which needs no arguments and returns an object having a duration
property equal to the value of the duration
variable at this scope. same with delay
. Note easing
is defined as the name, with the value of sineOut
.
This may be your issue if you just tried to put a literal 0
where delay
was. I see you tried making delayZero
, but used it likely in a different way than you intended. You probably meant to write this:
export const fadeOut = _ => ({
duration,
delay: 0,
easing: sineOut,
css: t => `opacity: ${t}`
});
When I tried this, it works just fine for me. Thanks for sharing your example.
If you want to include transition in _layout.svelte and don't need to include them in every route here is an alternative.
Here is a simple fly in/out from top transition.
<!-- src/component/PageTransitions.svelte -->
<script>
import { fly } from 'svelte/transition';
export let refresh = '';
</script>
{#key refresh}
<div
in:fly="{{ y: -50, duration: 250, delay: 300 }}"
out:fly="{{ y: -50, duration: 250 }}"
>
<slot/>
</div>
{/key}
And here is the layout component
<!-- src/routes/$layout.svelte for Svelte@next -->
<!-- src/routes/_layout.svelte for Sapper -->
<script>
import Nav from '../components/Nav';
import PageTransitions from '../components/PageTransitions';
export let segment;
</script>
<Nav {segment}/>
<PageTransitions refresh={segment}>
<slot/>
</PageTransitions>
And for completeness here is a simple Nav component
<!-- src/component/Nav.svelte -->
<script>
export let segment;
</script>
<style>
a {
text-decoration: none;
}
.current {
text-decoration: underline;
}
</style>
<div>
<a href="/" class='{segment === undefined ? "current" : ""}'>Home</a>
<a href="/about" class='{segment === "about" ? "current" : ""}'>About</a>
</div>
NOTES:
We make the component reactive by creating a refresh
prop and using key
directive which means that when the key changes, svelte removes the component and adds a new one, therefore triggering the transition.
In the layout component we pass the segment (route) as refresh
prop and therefore the refresh key changes as the route changes.
Here is a demo of the sample code above and the github repo