Search code examples
css-animationssveltesvelte-transition

how to animate:flip with in/out:fade?


I am trying to animate a changing list of elements, where some disappear, some move, and some appear.

Ideal animation sequence:

  1. Old elements fade out
  2. Existing elements move from old position to new position
  3. New elements fade in

The problem (bug?) is that the old elements, as they fade out, appear stacked on top of each other at the top or bottom of the list.

Can I not use animate:flip and transition:fade (in/out shorthand) at the same time?

REPL: https://svelte.dev/repl/5feb66e2ac544e10a11b98890c1b24dd?version=3.55.1

Code here for completeness:

<script>
    import { flip } from 'svelte/animate'
    import { fade } from 'svelte/transition'
    
    let startInt = 0
    $:items = Array(5).fill().map((x,i) => i+startInt)
    function shiftDown() {
        startInt = startInt + 3
    }
    function shiftUp() {
        startInt = startInt - 3
    }
</script>

<a href="#" on:click|preventDefault="{e => shiftUp()}">up</a>

{#each items as item (item)}
    <div
             animate:flip="{{delay: 1000, duration: 1000}}"
             in:fade="{{delay: 2000, duration: 1000}}"
             out:fade="{{duration: 1000}}"
    >
        {item}
    </div>
{/each}

<a href="#" on:click|preventDefault="{e => shiftDown()}">down</a>

List of items with buddy fade out


Solution

  • Wrapping the elements in a container with display: flex seems to solve the problem

    REPL

    <script>
        import { flip } from 'svelte/animate'
        import { fade } from 'svelte/transition'
    
        let startInt = 0
        $:items = Array(5).fill().map((x,i) => i+startInt)
        
        function shiftDown() {
            startInt = startInt + 3
        }
        function shiftUp() {
            startInt = startInt - 3
        }
    </script>
    
    <button on:click={shiftUp}>up</button>
    
    <div id="wrapper">
        {#each items as item (item)}
        <div
                 animate:flip="{{delay: 1000, duration: 1000}}"
                 in:fade="{{delay: 2000, duration: 1000}}"
                 out:fade="{{duration: 1000}}"
                 >
            {item}
        </div>
        {/each}
    </div>
    
    <button on:click={shiftDown}>down</button>
    
    <style>
        #wrapper {
            display: flex;
            flex-direction: column;
        }
    </style>