Custom Transitions And Staggered Transitions In Svelte(with AnimeJs)

manyeya

Khutso siema

Posted on November 1, 2019

Custom Transitions And Staggered Transitions In Svelte(with AnimeJs)

Let's start with the obvious.

Method #1

The first method will obviously to make use of the built-in transitions from svelte/transition and delay each element by its index.

Here's an example using the fly transition,
again this method is not limited to just the fly transition,you can use any transition from svelte/transition

<script>
import { fly } from "svelte/transition";
    let cats = [
      { id: 1, name: "Keyboard Cat" },
      { id: 2, name: "Maru" },
      { id: 3, name: "Henri The Existential Cat" }
    ];
let visible = false;

</script>

<input type="checkbox" bind:checked={visible}>
<ul>
{#each cats as {id,name},i}
  {#if visible}
    <h1 in:fly="{{x: -200,duration: 1000,delay:i*200 }}" 
out:fly="{{ x: 200, duration: 1000,delay:i*200 }}">{i +1}.{name}</h1>
  {/if}
{/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

But this method has some obvious limitations,you can only use it to transition one property at a time.

Method #2

To overcome the limitations of method 1# we can create our own custom transition.
for this example i modified the spin custom animation from the svelte official tutorial.

<script>
    import { fly } from "svelte/transition";
    import { elasticOut } from "svelte/easing";
    let cats = [
      { id: 1, name: "Keyboard Cat" },
      { id: 2, name: "Maru" },
      { id: 3, name: "Henri The Existential Cat" }
    ];
    let visible = false;

    function spin(node, { duration, delay }) {
      return {
        delay,
        duration,
        css: t => {
          const eased = elasticOut(t);
          return `transform: scale(${eased}) rotate(${eased * 360}deg);`
        }
      };
    }
</script>

<input type="checkbox" bind:checked={visible}>
<ul>
{#each cats as {name},i}
  {#if visible}
    <h1 in:spin="{{duration: 1000,delay:i*200 }}" 
out:fly="{{ x: 200, duration: 1000,delay:i*200 }}">{i +1}.{name}</h1>
  {/if}
{/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

Let's break this down starting with spin(node, { duration, delay })

node - refers to the element being transitioned
duration -refers to the time it will take to complete the transition
delay - refers the time between transitions

the css function returns a css animation and has parameters t and u
t value is 0 at the beginning of an intro or the end of an outro, and 1 at the end of an intro or beginning of an outro,and u its the opposite of t

so our scale property is transitioned from 0 to 1

Method #3

the first two methods are great for simple transitions,for complicated animations we will need something extra,that extra something something for me is AnimeJs

Let's start by installing animejs

npm install animejs --save
Enter fullscreen mode Exit fullscreen mode

Now lets modify our code once more

<script>
    import anime from "animejs/lib/anime.es.js";
    let cats = [
      { id: 1, name: "Keyboard Cat" },
      { id: 2, name: "Maru" },
      { id: 3, name: "Henri The Existential Cat" }
    ];
    let visible = false;

    function reverse(node, { targets, duration }) {
    return {
      css: t => {
        return anime({
          targets,
          duration,
          easing: "easeInOutCirc",
          opacity: [1, 0],
          translateX: [0, -500],
          scale: [1, 0],
          delay: anime.stagger(200),
        });
      }
    };

  }
    function forward(node, { targets, duration }) {
    return {
      css: t => {
        anime({
          targets,
          duration,
          easing: "easeInOutCirc",
          opacity: [0, 1],
          translateX: [-500, 0],
          scale: [0, 1],
          delay: anime.stagger(200)
        });
      }
    };

  }
</script>

<input type="checkbox" bind:checked={visible}>
<ul>
{#each cats as {name},i}
  {#if visible}
    <h1 class="animate"
         in:forward="{{ targets: '.animate', duration: 1500 }}"
         out:reverse="{{ targets: '.animate', duration: 1500 }}">
         {i +1}.{name} 
    </h1>
  {/if}
{/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

In this example i made two transitions instead of one,

and as you might have noticed i used targets to refer to the elements instead of node,this is due to the fact that node only refers to one element.
And another confusing thing is that i used css function instead of the tick function,this was due to the performance issues i got by using tick and animejs seems to return css animations this might explain why this works(don't qoute me on this)


Thanks for reading and stay tuned!

💖 💪 🙅 🚩
manyeya
Khutso siema

Posted on November 1, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related