Переходы и анимации
Переход (transition) — анимация, которая проигрывается, когда элемент появляется на странице или исчезает с неё. В Svelte готовые переходы подключаются одной директивой, без CSS-ключевых кадров и отдельных библиотек.
Директива transition
Готовые переходы лежат в модуле svelte/transition. Самый простой — fade, плавное появление и исчезновение:
<!-- src/routes/+page.svelte -->
<script>
import { fade } from 'svelte/transition';
let showHint = $state(true);
</script>
<button onclick={() => (showHint = !showHint)}>Подсказка</button>
{#if showHint}
<p transition:fade>Отмечайте выполненные задачи галочкой.</p>
{/if}Кнопка прячет и показывает абзац, и каждый раз он плавно тает или проявляется. Переход срабатывает, когда элемент добавляется или удаляется блоком {#if} или {#each}.
Параметры
Переходу можно передать объект настроек:
<script>
import { fly } from 'svelte/transition';
let showHint = $state(true);
</script>
{#if showHint}
<p transition:fly={{ y: -20, duration: 300 }}>Новая подсказка</p>
{/if}Абзац прилетает сверху на 20 пикселей за 300 миллисекунд. Двойные фигурные скобки — это объект внутри выражения.
| Переход | Что делает |
|---|---|
fade | меняет прозрачность |
fly | сдвигает и меняет прозрачность |
slide | раскрывает по высоте |
scale | увеличивает или уменьшает |
Разные переходы на вход и выход
Директивы in: и out: задают переходы отдельно для появления и исчезновения:
<!-- src/routes/+page.svelte: строка списка задач -->
<script>
import { fly, fade } from 'svelte/transition';
let todos = $state([{ id: 1, text: 'Купить хлеб' }]);
</script>
<ul>
{#each todos as todo (todo.id)}
<li in:fly={{ x: -30 }} out:fade>{todo.text}</li>
{/each}
</ul>Новая задача выезжает слева, а удалённая тихо растворяется.
Анимация перестановки
Когда элементы списка меняют порядок, функция flip из модуля svelte/animate плавно переносит их на новые места. Она работает только в блоке {#each} с ключом:
<script>
import { flip } from 'svelte/animate';
let todos = $state([
{ id: 1, text: 'Купить хлеб' },
{ id: 2, text: 'Позвонить Олегу' }
]);
</script>
<button onclick={() => todos.reverse()}>Перевернуть</button>
<ul>
{#each todos as todo (todo.id)}
<li animate:flip={{ duration: 300 }}>{todo.text}</li>
{/each}
</ul>После клика строки не прыгают, а плавно меняются местами.
Частая ошибка
Ставить transition: на элемент, который всегда на странице, и ждать анимации при изменении текста. Переход проигрывается только при добавлении и удалении элемента. Чтобы он сработал, оберните элемент в {#if} или {#each}.