How to do page transitions with svelte/sapper
Asked Answered
M

4

7

I want to realize a simple page (route) transition in Sapper. Something that is easily achievable with Nuxt for example. Does anyone have an idea how to realize that with Sapper?

I already wrapped my page content into a div with a transition:fade directive. This works. Yet, the two pages transition at the same time, meaning while one page transitions out the other one already transitions in. It would be great if someone pointed me in the right direction. Thanks!

Myxoma answered 12/8, 2019 at 15:30 Comment(0)
S
11

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}`
});
  1. The delayZero variable is there because for some reason it won't take '0' directly and will break.
  2. 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

Sideward answered 17/8, 2019 at 19:20 Comment(1)
If I want the same transition for all pages, do I need to add an individual transition to each page component or is there a way to add it in one place and have it executed for pages components?Turpin
O
6

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 Sapper layout component

<!-- src/routes/_layout.svelte for Sapper -->

<script>
  import { page } from '$app/stores'; // svelte@next
  import Nav from '../components/Nav';
  import PageTransitions from '../components/PageTransitions';
  export let segment;
</script>

<Nav {segment}/>

<PageTransitions refresh={segment}>
  <slot/>
</PageTransitions>

And here is the SvelteKit (svelte@next) layout component

<!-- src/routes/$layout.svelte for Svelte@next -->

<script>
  import { page } from '$app/stores'; // svelte@next
  import Nav from '../components/Nav';
  import PageTransitions from '../components/PageTransitions';
</script>

<Nav segment={$page.path}/>

<PageTransitions refresh={$page.path}>
  <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

Otten answered 20/11, 2020 at 20:2 Comment(2)
It's important to warn to change for the navigation elements the CSS z-index as well as the CSS position to relative in order to not fight with the animation.Siege
Additionally, for Sapper your code is wrong/outdated. Instead of using "import { page } from '$app/stores';", you need to import page store this way: sapper.svelte.dev/docs#StoresSiege
A
3

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.

Alkyl answered 1/1, 2020 at 6:43 Comment(0)
D
0

I guess Svelte Kit has changed since @GiorgosK answer, because I cannot make it work with the code in his answer. But fortunately, his github repo has been update with the solution, thanks ! The page.path properties much be used in module context

This is my version without a specific component for page transition :

    <!-- src/route/__layout.svelte -->
    <script context="module">
        export const load = async ({ page }) => ({
            props: {
                key: page.path,
            },
        });
    </script>
    
    <script>
        import { fly } from "svelte/transition";
        export let key;
    </script>
    
    <nav>
        <a href="/foo">foo</a>
        <a href="/bar">bar</a>
    </nav>
    
    {#key key}
        <div
            in:fly={{ x: 50, duration: 2500 }}
            out:fly={{ y: -50, duration: 2500 }}
        >
            <slot />
        </div>
    {/key}

Maybe @GiorgosK can share some insight about that change.

Descend answered 11/8, 2021 at 11:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.