Custom Transitions And Staggered Transitions In Svelte(with AnimeJs)
Khutso siema
Posted on November 1, 2019
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>
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>
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
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>
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!
Posted on November 1, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.