sveltesveltekitsvelte-transition

Is it possible to have overlapping page transitions in Svelte?


Say I have an out: transition on an element in a SvelteKit route "A" and another in: transition on some other element in route "B". Wenn navigating from page A to B, the transition of A has to finish before the elements of page B are shown.

Is there a way to have the elements of page A and B overlap during their transitions?

Page A
<script>
    import { fly } from "svelte/transition";
</script>

<header out:fly={{ y: 100 }}>
...
Page B
...
<header in:fly={{ y: 100 }}>
...
File structure
πŸ“¦β€‰project
 β”” πŸ“‚β€‰src
   β”” πŸ“‚β€‰routes 
      β”œ πŸ“œ route-a.svelte
      β”” πŸ“œ route-b.svelte

Solution

  • As I see in Svelte 3.48.0 + SvelteKit 1.0.0-next.350, the problem is not "transition of A has to finish before the elements of page B are shown", because SvelteKit starts "Page A" and "Page B" transitions after the "Page B" is loaded. You can see it if you add (uncomment) a delay to the src/routes/b.js endpoint in my example below.

    The problem is with the fly transition and CSS β€” "Page A" occupies a space until "Page A" transition is finished. You can solve this by this workaround (the one used in my example below) or by using another transition (slide, for example).

    Worked example with fly transition overlapping

    src/routes/__layout.svelte:

    <nav>
        <a href='/a'>Page A</a> | <a href='/b'>Page B</a>
    </nav>
    
    <div>
        <slot/>
    </div>
    
    <style>
        div {
            display: grid;
            grid-template-rows: 1fr;
            grid-template-columns: 1fr;
        }
    
        div>:global(*) {
            grid-row: 1;
            grid-column: 1;
        }
    </style>
    

    src/routes/a.svelte:

    <script>
        import { fly } from 'svelte/transition'
    </script>
    
    <header out:fly={{ y: 100, duration: 2000 }}>
    aaaaaaa
    </header>
    
    <style>
        header {
            height: 200px;
            background: #eee;
        }
    </style>
    

    src/routes/b.svelte:

    <script>
        import { fly } from 'svelte/transition'
        export let text
    </script>
    
    <header in:fly={{ y: 100, duration: 2000 }}>
    {text}
    </header>
    
    <style>
        header {
            height: 200px;
            background: #eee;
        }
    </style>
    

    src/routes/b.js:

    import { setTimeout } from 'timers/promises'
    
    export async function get() {
        // await setTimeout(1000)
        return {
            body: {
                text: 'bbbbbbbbb'
            }
        }
    }