Cours Svelte et SvelteKit · Module 9: Transitions et animations
Motion : Tween et Spring
Dans cette leçon4
Le module svelte/motion propose deux classes pour faire évoluer une valeur en douceur : Tween et Spring (depuis Svelte 5.8). Les deux ont deux champs importants :
target- la valeur visée (tu peux l'affecter),current- la valeur actuelle animée (en lecture seule et réactive).
La méthode set(valeur, options) fixe aussi la cible et renvoie une Promise résolue à la fin de l'animation.
Tween - Transitions de valeurs fluides
<script>
import { Tween } from 'svelte/motion';
import { cubicOut } from 'svelte/easing';
const progress = new Tween(0, {
duration: 400,
easing: cubicOut
});
</script>
<button onclick={() => progress.target = 100}>100%</button>
<button onclick={() => progress.target = 0}>0%</button>
<progress value={progress.current} max="100"></progress>
<p>{Math.round(progress.current)}%</p>
<style>
progress {
width: 100%;
height: 20px;
}
</style>Spring - Physique du ressort
<script>
import { Spring } from 'svelte/motion';
const coords = new Spring({ x: 50, y: 50 }, {
stiffness: 0.1, // rigidité
damping: 0.5 // amortissement
});
function handleMouseMove(e) {
coords.target = {
x: e.clientX,
y: e.clientY
};
}
</script>
<svelte:window onmousemove={handleMouseMove} />
<svg>
<circle cx={coords.current.x} cy={coords.current.y} r="20" fill="gold" />
</svg>Exemple : graphique animé
<script>
import { Tween } from 'svelte/motion';
const data = new Tween([10, 20, 30, 40, 50], { duration: 500 });
function randomize() {
data.target = Array(5).fill(0).map(() => Math.random() * 100);
}
</script>
<button onclick={randomize}>Randomize</button>
<div class="chart">
{#each data.current as value, i}
<div class="bar" style="height: {value}%">
{Math.round(value)}
</div>
{/each}
</div>
<style>
.chart {
display: flex;
gap: 10px;
height: 200px;
align-items: flex-end;
}
.bar {
flex: 1;
background: gold;
transition: height 0.3s;
}
</style>L'ancienne API : tweened et spring
Avant Svelte 5.8, on utilisait les fonctions tweened() et spring(), qui renvoient des stores lus avec $progress. Elles fonctionnent encore, mais elles sont marquées comme obsolètes (deprecated). Dans du nouveau code, choisis les classes Tween et Spring.
// Avant (store)
const progress = tweened(0); // dans le template : {$progress}
// Svelte 5
const progress = new Tween(0); // dans le template : {progress.current}Code de cette leçon : App.svelte
<script>
// Motion : les classes Tween et Spring (Svelte 5)
import { Tween, Spring } from 'svelte/motion';
import { cubicOut } from 'svelte/easing';
// Tween - interpolation fluide d’une valeur sur une durée donnée
const progress = new Tween(0, {
duration: 400,
easing: cubicOut
});
// Spring - animation avec une physique de ressort
const coords = new Spring({ x: 50, y: 50 }, {
stiffness: 0.1,
damping: 0.25
});
function handleMouseMove(e) {
const rect = e.currentTarget.getBoundingClientRect();
coords.set({
x: e.clientX - rect.left,
y: e.clientY - rect.top
});
}
</script>
<main class="motion-demo">
<h1>Motion : Tween et Spring</h1>
<section>
<h2>Tween - Barre de progression</h2>
<div class="progress-bar">
<div class="fill" style="width: {progress.current}%"></div>
</div>
<p>{Math.round(progress.current)}%</p>
<div class="buttons">
<button onclick={() => progress.target = 0}>0%</button>
<button onclick={() => progress.target = 50}>50%</button>
<button onclick={() => progress.target = 100}>100%</button>
</div>
</section>
<section>
<h2>Spring - Élément suiveur</h2>
<div class="spring-area" onmousemove={handleMouseMove}>
<div
class="follower"
style="left: {coords.current.x}px; top: {coords.current.y}px"
>
ᛏ
</div>
<p class="hint">Déplace le curseur</p>
</div>
</section>
</main>
<style>
.motion-demo {
font-family: 'Georgia', serif;
max-width: 500px;
margin: 0 auto;
padding: 2rem;
background: #1a0a0a;
color: #f7d5e8;
min-height: 100vh;
}
h1 {
color: #ff6b6b;
text-align: center;
}
section {
background: rgba(255, 107, 107, 0.1);
border: 1px solid #ff6b6b;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
}
h2 {
color: #ff6b6b;
font-size: 1rem;
margin-top: 0;
}
.progress-bar {
height: 30px;
background: rgba(0,0,0,0.5);
border-radius: 15px;
overflow: hidden;
margin-bottom: 0.5rem;
}
.fill {
height: 100%;
background: linear-gradient(90deg, #ff6b6b, #ffd700);
border-radius: 15px;
}
.buttons {
display: flex;
gap: 0.5rem;
}
button {
flex: 1;
padding: 0.5rem;
background: #3a1a2a;
color: #f7d5e8;
border: 1px solid #ff6b6b;
border-radius: 4px;
cursor: pointer;
}
.spring-area {
position: relative;
height: 200px;
background: rgba(0,0,0,0.3);
border-radius: 8px;
overflow: hidden;
}
.follower {
position: absolute;
font-size: 2rem;
transform: translate(-50%, -50%);
pointer-events: none;
}
.hint {
position: absolute;
bottom: 10px;
width: 100%;
text-align: center;
color: #a87ca8;
font-size: 0.85rem;
}
</style>Entrées de la documentation utilisées dans cette leçon
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. En quoi Spring diffère-t-il de Tween ?