{:else if stat" /> {:else if stat" /> {:else if stat"/>

Svelte if-else connecting transitions

43 Views Asked by At

I have a page that has several stages, and I want to add transitions between them.

{#if state === 1}
 <div class="red" transition:fade/>
{:else if state === 2}
 <div class="blue" transition:fade/>
{:else if state === 3}
 <div class="green" transition:fade/>
{/if}

However, when switching from one state to the next, the next one appears at the same time as the previous one is still disappearing, so the two states would appear at the same time for the duration of the transition.

What is the best approach (the approach that requires adding the least amount of code) to make one state's fade in connect with another state's fade out?

Here is a code sandbox link: https://codesandbox.io/p/sandbox/priceless-pine-kgrh7w

2

There are 2 best solutions below

0
Corrl On BEST ANSWER

One way would be to position the elements on top of each other with the help of a wrapper element

REPL

<script>
    import { fade } from 'svelte/transition';
    let state = 1;

    function handleClick() {
        state += 1;
        if (state == 4) state = 1;
    }
</script>

<main>
    <button on:click={handleClick}> Change </button>
    <div class="wrapper">
        {#if state === 1}
            <div class="red" transition:fade/>
        {:else if state === 2}
            <div class="blue" transition:fade/>
        {:else if state === 3}
            <div class="green" transition:fade/>
        {/if}
    </div>
</main>

<style>
    button {
        background: #ff3e00;
        color: white;
        border: none;
        padding: 8px 12px;
        border-radius: 2px;
    }

    .wrapper {
        display: grid;      
    }

    .wrapper > div {
        grid-column: 1;
        grid-row: 1;
        width: 100px;
        height: 100px;
    }

    .red {
        background: red;
    }

    .blue {
        background: blue;
    }

    .green {
        background: green;
    }
</style>
0
brunnerh On

I often use a wrapper to stack items in place:

.stack { display: grid; }
.stack > * { grid-area: 1 / 1; } /* potentially add place-self to center */

REPL

This will cause an overlapping fade.

If that is not what you want, you can instead add a delay to to each transition that waits for the previous one to finish.

const inOptions = { duration: 400, delay: 400 };
const outOptions = { duration: 400 };
{#if state === 1}
 <div class="red" in:fade={inOptions} out:fade={outOptions}/>
{:else if state === 2}
 <div class="blue" in:fade={inOptions} out:fade={outOptions}/>
{:else if state === 3}
 <div class="green" in:fade={inOptions} out:fade={outOptions}/>
{/if}

REPL

(The stack could still be added for safety if animations end up not fully in sync. Or increase the delay to a bit more than the duration.)