loading...

Fluid page transitions with Svelte & Sapper

buhrmi profile image Stefan Buhrmester ・Updated on ・2 min read

Ever came across websites with cool animations whenever navigating from one page to another? For example this website by Sarah Drasner. Usually, you'd use client-side libraries and clever CSS tricks to achieve these sort of things. Probably nothing wrong with that, but it adds to your website's overall download size, and your CSS will become hard to maintain as your site grows in complexity. However, thanks to Svelte, we can now do these cool things without any client-side library or CSS trickery:

GREAT SUCCESS
(Try it out)

So now we can have cool PWAs, that are server-side rendered, have smooth page transitions, and are compiled down to really tiny amounts of javascript. With no need for client-side libraries, runtimes, virtual DOMs, or shuffling CSS classes around. Oouwee!

And with that, our lives are now complete. Because what else could we possibly want? We should now all go and praise Rich Harris the JavaScript God. Or do we need more JavaScript frameworks? Don't we have enough? I can't take it anymore. Make it stop. Aaaaaahhh this is the end.

These animations all use Svelte's crossfade transition. If you haven't used it before, work through the tutorial and then come back here. The trick to making the crossfade transition work across different pages (or components) defined in separate files, is to create the crossfade transition in its own module/file, and import it into the different components. Check it out:

crossfade.js

import { quintOut } from 'svelte/easing';
import { crossfade } from 'svelte/transition';
const [send, receive] = crossfade({
    duration: d => Math.sqrt(d * 300),
    fallback(node, params) {
        const style = getComputedStyle(node);
        const transform = style.transform === 'none' ? '' : style.transform;

        return {
            duration: 600,
            easing: quintOut,
            css: t => `
                transform: ${transform} scale(${t});
                opacity: ${t}
            `
        };
    }
});

export {send, receive};
Enter fullscreen mode Exit fullscreen mode

page1.svelte

<script>
  import {send, receive} from './crossfade.js';
</script>

<main>
  <h1 out:send="{{key: 'h1'}}" in:receive="{{key: 'h1'}}">Look, I'm above the image</h1>
  <img out:send="{{key: 'borat'}}" in:receive="{{key: 'borat'}}" alt='Borat' src='great-success.png'>
</main>

Enter fullscreen mode Exit fullscreen mode

page2.svelte

<script>
  import {send, receive} from './crossfade.js';
</script>

<main>
  <img out:send="{{key: 'borat'}}" in:receive="{{key: 'borat'}}" alt='Borat' src='great-success.png'>
  <h1 out:send="{{key: 'h1'}}" in:receive="{{key: 'h1'}}">Now I am below the image</h1>
</main>

Enter fullscreen mode Exit fullscreen mode

global.css

main {
  position: absolute;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

There you go.

Discussion

pic
Editor guide
Collapse
doppelganger9 profile image
David Lacourt

Hi, thanks for providing the changes and some examples.
It can lead to great effects in the UI, and it seems to be easy to achieve with what you've done.
I'm curious where did you get the idea? some other framework/library?

Collapse
buhrmi profile image
Stefan Buhrmester Author

No, I was looking at this site and thought it'd be cool if there was a way to achieve this sort of effect with built-in Svelte tools only.

Collapse
doppelganger9 profile image
David Lacourt

Okay, thanks!

This kind of animations are so cool!

If I follow the "inspiration chain", I see the influence of Sarah Drasner's work, I knew it ;-)

I once saw her live, back in 2017, and my mind was blown 🀯:

Collapse
giorgosk profile image
Giorgos Kontopoulos πŸ‘€

Stefan, this is great stuff thanks for posting

Collapse
franz profile image
Franz Sittampalam

this is hot, thanks for sharing

Collapse
stunjiturner profile image
S Tunji Turner

thanks for the post, I am having issues with the crossfade.js during deployment to now. the node_modules folder is in the .nowignore file as best practices? any ideas?