Transisi adalah animasi yang Svelte jalankan saat sebuah elemen masuk ke DOM atau keluar dari DOM, misalnya toast "Nasi Goreng masuk keranjang" yang muncul perlahan lalu memudar. Bayangin pelayan Warung Bu Sri mengantar piring. Piringnya gak tiba-tiba ada di meja: tangan pelayan membawanya masuk dari samping. Waktu diangkat, piringnya dibawa keluar pelan-pelan juga. Tapi kalau lauknya ditambah, piringnya gak diantar ulang. Transisi Svelte sama: jalan saat elemen datang dan pergi, bukan saat isinya berubah.
🧪 Tebakan cepat: toast
<div transition:fade>ada di dalam{#if tampil}, dan blok itu ada di dalam{#if panelBuka}. Pembeli menutup panelnya saat toast sedang tampil. Toast-nya memudar 400 ms, atau langsung hilang? Jawabannya ada di bagian "Lokal dan |global".
transition:fade
<script>
import { fade } from "svelte/transition"
let tampil = false
</script>
<button on:click={() => (tampil = true)}>Tambah Nasi Goreng</button>
{#if tampil}
<div class="toast" transition:fade>
Nasi Goreng masuk keranjang
<button on:click={() => (tampil = false)}>Tutup</button>
</div>
{/if}
| Kejadian | Yang terjadi |
|---|---|
| Klik Tambah Nasi Goreng | <div> dipasang, opacity naik dari 0 ke 1 selama 400 ms |
| Klik Tutup | opacity turun dari 1 ke 0 selama 400 ms, baru setelah itu <div> dilepas dari DOM |
fadediimpor dari modul"svelte/transition". Modul yang sama punyafly,slide,scale,blur, dandraw(untuk garis SVG).transition:fadeadalah directive transisi: atribut khusus Svelte yang memasang animasi masuk (intro) dan animasi keluar (outro) sekaligus.- Transisi cuma jalan saat elemennya benar-benar dipasang atau dilepas, jadi elemennya harus ada di dalam
{#if}atau{#each}. Menyembunyikannya dengan CSSdisplay: nonegak menjalankan apa-apa. - Selama outro, elemennya masih ada di DOM. Svelte baru melepasnya setelah 400 ms itu selesai.
- Mengganti teks di dalam toast yang sedang tampil gak menjalankan transisi, karena elemennya gak pergi. Untuk memutarnya lagi, bungkus dengan
{#key nama}: tiapnamaberubah, elemen lamanya keluar dan elemen barunya masuk.
Parameter: durasi, jeda, arah
Tiap transisi menerima objek parameter. Kurung kurawal luarnya milik Svelte, yang dalam adalah objek JavaScript:
<div class="toast" transition:fly={{ y: -20, duration: 300, delay: 100 }}>
Nasi Goreng masuk keranjang
</div>
| Transisi | Nilai bawaannya |
|---|---|
fade |
duration: 400, delay: 0, easing linear |
fly |
duration: 400, delay: 0, x: 0, y: 0, opacity: 0, easing cubicOut |
slide |
duration: 400, axis: "y", easing cubicOut |
scale |
duration: 400, start: 0, easing cubicOut |
y: -20berarti toast mulai 20 px di atas tempatnya, lalu turun ke tempatnya sambil makin terlihat. Saat keluar, dia naik lagi 20 px sambil memudar.durationdalam milidetik.delay: 100menunggu 100 ms dulu sebelum mulai.- Latihan kedua memakai bentuk ini:
transition:fly={{ y: -50, duration: 400 }}, masuk dari 50 px di atas selama 400 ms.
in: dan out: terpisah
<div class="toast" in:fly={{ y: -20, duration: 300 }} out:fade={{ duration: 200 }}>
Nasi Goreng masuk keranjang
</div>
in:cuma untuk masuk,out:cuma untuk keluar. Toast ini terbang masuk 300 ms, lalu memudar keluar 200 ms.transition:bisa berbalik arah. Kalau Tutup diklik saat toast baru setengah masuk, animasinya mundur dari titik itu.in:danout:gak berbalik:out:mulai dari awalnya sendiri, sementarain:tetap jalan sampai selesai.
Lokal dan |global
{#if panelBuka}
<section class="panel">
{#if tampil}
<div class="toast" transition:fade>Nasi Goreng masuk keranjang</div>
{/if}
</section>
{/if}
- Di Svelte 4, transisi itu lokal: dia cuma jalan saat blok miliknya sendiri,
{#if tampil}, yang memasang atau melepasnya. - Saat
panelBuka = false, yang melepas adalah blok luar. Transisi lokal gak jalan, jadi toast-nya langsung hilang bersama panelnya. Itu jawaban tebakannya. transition:fade|globalmembuatnya ikut jalan saat blok luar yang memasang atau melepas. Panelnya lalu tetap ada 400 ms sampai toast selesai memudar.- Di Svelte 3, bawaannya kebalikannya (global).
|localmasih boleh ditulis di Svelte 4, artinya sama dengan bawaannya.
📌 Intro saat halaman pertama dibuka
Elemen yang sudah ada saat komponen pertama kali dipasang gak menjalankan intro. let tampil = true membuat toast langsung tampil, tanpa memudar masuk. Itu sebabnya paragraf di latihan langsung terlihat. new App({ target, intro: true }) di main.js memutar intro di render pertama, tapi di Svelte 4 cuma untuk transisi |global.
📌 Easing dan gerakan yang dikurangi
easing adalah function yang mengubah kemajuan animasi dari 0 sampai 1 jadi kurva gerak. Svelte menyediakannya di "svelte/easing", misalnya cubicOut dan elasticOut, dan kamu boleh menulis sendiri: easing: (t) => t * t mulai pelan lalu makin cepat.
Sebagian pengguna menyalakan setelan "kurangi gerakan" di perangkatnya. Svelte gak membacanya otomatis, jadi baca sendiri:
const kurangiGerak = window.matchMedia("(prefers-reduced-motion: reduce)").matches
// lalu: transition:fly={{ y: kurangiGerak ? 0 : -20, duration: kurangiGerak ? 0 : 300 }}
Di SvelteKit, yang juga merender di server, baca nilainya di onMount. Svelte 5 menyediakan prefersReducedMotion.current dari "svelte/motion".
Latihan: fade dan fly
Latihan pertama cukup menambah import dan directive-nya ke kode awal: import { fade } from "svelte/transition" dan <p transition:fade>Teks dengan fade</p>. Latihan kedua ditulis lengkap:
<script>
import { fly } from "svelte/transition"
let visible = true
</script>
<button on:click={() => (visible = !visible)}>Toggle</button>
{#if visible}
<p transition:fly={{ y: -50, duration: 400 }}>Terbang dari atas!</p>
{/if}
Penguji menekan tombol bertulisan Toggle, lalu memeriksa bahwa <p> sudah gak ada di halaman. Dia menunggu sekitar satu detik, jadi outro 400 ms sempat selesai.
Svelte 5
transition:, in:, out:, |global, dan semua fungsi di "svelte/transition" sama di Svelte 5. Bedanya cuma di sekitarnya: let visible = $state(true) dan onclick.
⚠️ Jebakan yang sering ketemu
- Menyembunyikan dengan CSS.
style:displayatauclass:hiddengak memasang atau melepas elemen, jadi gak ada transisi. Pakai{#if}; latihannya juga memeriksa{#ifdanon:click. - Kurung kurawal tunggal.
transition:fly={ y: -50 }ditolak compiler denganExpected }. Parameternya objek, jadi tulis{{ y: -50 }}. - Lupa mengimpor. Tanpa
import { fade }, compiler cuma memberi warning'fade' is not defined, lalu saat tombolnya diklik munculReferenceError: fade is not defined. - Mengira transisi selalu jalan. Gak jalan di render pertama, dan gak jalan saat blok luar yang menutup, kecuali
|global.
TL;DR: Transisi jalan saat elemen dipasang atau dilepas lewat {#if} atau {#each}, bukan saat isinya berubah. Impor dari "svelte/transition" (fade, fly, slide, scale, blur, draw), lalu pasang transition:fade untuk masuk dan keluar, atau in:fly dan out:fade terpisah. Parameternya objek dalam kurung kurawal ganda, misalnya {{ y: -20, duration: 300, delay: 100 }}; fade dan fly berjalan 400 ms kalau gak diatur. transition: bisa berbalik di tengah jalan, in: dan out: gak. Di Svelte 4 transisi itu lokal: gak jalan saat blok luar yang menutup, kecuali |global, dan gak jalan di render pertama. Untuk pengguna yang mengurangi gerakan, baca prefers-reduced-motion dan pakai duration: 0. Latihannya: <p transition:fade>Teks dengan fade</p>, dan tombol Toggle dengan <p transition:fly={{ y: -50, duration: 400 }}>Terbang dari atas!</p> di dalam {#if visible}.