CSS Transitions — Web Animation

CSS Transitions CSS Transition memungkinkan kamu menganimasi perubahan properti CSS secara halus. Alih-alih perubahan terjadi instan, transition membuat…

CSS transition membuat perubahan nilai CSS terjadi pelan-pelan, bukan langsung loncat. Bayangin saklar lampu biasa dan saklar dimmer. Saklar biasa: ditekan, lampunya langsung terang. Dimmer: kamu tetap memutarnya ke "terang", tapi cahayanya naik bertahap. transition mengubah saklar biasa jadi dimmer: kamu tetap mengganti nilainya (lewat kelas, :hover, atribut), dan browser yang mengisi nilai-nilai di antaranya.

🧪 Tebakan cepat: Tombol "3 malam" punya transition: all 150ms ease-out. Saat dipilih, warna latar, warna teks, dan warna garisnya berubah. Event transitionend datang berapa kali? Jawabannya ada di bagian "transitionend: satu event per properti".

Menulis transition

transition adalah shorthand dari empat properti:

Longhand Isinya Default
transition-property properti yang dianimasikan all
transition-duration lamanya, wajib pakai satuan: 0.3s atau 300ms 0s
transition-timing-function kurva kecepatan (easing) ease
transition-delay jeda sebelum mulai 0s

Urutan di shorthand: properti, durasi, easing, delay. Nilai waktu pertama selalu durasi, yang kedua delay. Beberapa transisi digabung dengan koma. Ini tombol malam di halaman Bu Sri:

.nights button {
  color: #1f2937;
  background: #fff;
  border: 1px solid #475569;
  transition: background-color 150ms ease-out, color 150ms ease-out, border-color 150ms ease-out;
}
.nights button[aria-pressed="true"] {
  color: #fff;
  background: #15803d;
  border-color: #15803d;
}

Di latihan kamu merakit string itu dengan JavaScript. Satu transisi = tiga bagian dipisah spasi, beberapa transisi = digabung dengan ", ":

Masukan Hasil
"opacity", "0.3s", "ease-out" opacity 0.3s ease-out
dua objek: opacity 0.3s ease, transform 0.5s ease-out opacity 0.3s ease, transform 0.5s ease-out
satu objek: width 1s steps(4) width 1s steps(4), tanpa koma

Delay: kapan transisinya selesai?

Waktu total = delay + durasi. Dengan transition: opacity 0.3s ease-in 0.1s;, 0,1 detik pertama gak ada yang bergerak, lalu opacity berubah selama 0,3 detik. Selesai di 0,4 detik setelah nilainya diganti.

Browser mengirim event di setiap tahap. Kami mengukur transition: opacity 200ms ease-out 100ms di Chromium 147, WebKit 26.4, dan Firefox 146:

Event Artinya Datang di
transitionrun transisi dibuat, delay mulai dihitung 3 sampai 14 ms
transitionstart delay habis, nilai mulai berubah 104 sampai 116 ms
transitionend nilai sampai di tujuan 303 sampai 313 ms

Tombol Pesan: hover, focus, dan ditekan

.book {
  background: #15803d;
  outline: 3px solid transparent;
  outline-offset: 0;
  transition: background-color 150ms ease-out, outline-color 150ms ease-out,
              outline-offset 150ms ease-out, transform 100ms ease-out;
}
.book:hover { background: #166534; }                         /* hijau lebih gelap */
.book:focus-visible { outline-color: #166534; outline-offset: 3px; } /* cincin fokus keyboard */
.book:active { transform: scale(0.98); }                     /* sedikit mengecil saat ditekan */

Browser selalu memakai transition dari state tujuan. Kalau transition cuma ada di .book:hover, masuk ke hover beranimasi, tapi keluar dari hover langsung loncat, karena state tujuannya (.book) gak punya transition. Aturan yang sama bisa kamu manfaatkan: buka 200 ms, tutup 150 ms, seperti dialog di bawah.

Mana yang bisa di-transition

Properti yang nilainya punya "di antara" bisa diinterpolasi: angka, panjang, persen, warna, opacity, transform, box-shadow. Properti yang nilainya pilihan kata, seperti display (none atau block) atau position, disebut diskret: gak ada nilai setengah none. Jadi properti yang gak bisa dianimasikan transition biasa adalah display. visibility pengecualian: dia ikut ber-transisi, dan selama transisinya elemen tetap visible (kami ukur di tengah transisi: visible di ketiga browser).

Dua fitur baru membuat elemen bisa muncul dan hilang dengan animasi:

.modal {
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 150ms ease-in, transform 150ms ease-in,
              display 150ms allow-discrete, overlay 150ms allow-discrete;
}
.modal[open] {
  opacity: 1;
  transform: none;
  transition-duration: 200ms;          /* buka lebih pelan dari tutup */
  transition-timing-function: ease-out;
}
@starting-style {
  .modal[open] { opacity: 0; transform: scale(0.96); }
}

Kami membuka dan menutup <dialog> ini dengan showModal() dan close(). Buka beranimasi di Chromium 147, WebKit 26.4, dan Firefox 146. Tutup beranimasi di Chromium dan WebKit; di Firefox dialognya langsung hilang. overlay (dialog tetap di lapisan paling atas selama animasi tutup) baru ada di Chrome 117 ke atas; browser lain mengabaikan baris itu dengan aman.

transitionend: satu event per properti

transitionend datang sekali untuk tiap properti yang selesai berpindah. Kami memilih tombol "3 malam" dengan dua versi CSS, di ketiga browser:

transition di tombol transitionend yang datang
all 150ms ease-out 6: background-color, color, border-top-color, border-right-color, border-bottom-color, border-left-color
background-color 150ms ease-out 1: background-color

Itu jawaban tebakannya: 6 kali. border-color adalah shorthand dari empat sisi, dan tiap sisi mendapat event sendiri. Karena itu listener selalu mengecek e.propertyName:

toast.addEventListener('transitionend', (e) => {
  if (e.propertyName !== 'opacity') return; // tunggu satu properti saja
  if (!toast.classList.contains('show')) toast.hidden = true;
});

transitionend gak datang kalau nilainya gak berubah (kelas baru tapi nilainya sama), kalau durasinya 0s atau transition: none, dan kalau elemennya jadi display: none di tengah jalan. Yang terakhir mengirim transitioncancel (Chrome 87, Firefox 53, Safari 13.1); kami melihatnya di ketiga browser.

⚠️ Jebakan yang sering ketemu

TL;DR: transition = properti, durasi, easing, delay (opacity 0.3s ease-out), beberapa digabung dengan koma; durasi wajib bersatuan. Waktu total = delay + durasi: opacity 0.3s ease-in 0.1s selesai di 0,4 detik, dengan transitionrun di awal, transitionstart setelah delay, transitionend di akhir. Tulis transition di aturan dasar; browser memakai transition dari state tujuan. Yang bisa diinterpolasi: angka, panjang, warna, opacity, transform; display diskret dan gak bisa di-transition biasa. allow-discrete (Chrome 117, Firefox 129, Safari 17.4) dan @starting-style (Chrome 117, Firefox 129, Safari 17.5) membuat elemen bisa muncul dengan animasi; animasi keluar lewat display jalan di Chrome 117 dan Safari 18, belum di Firefox. transitionend datang sekali per properti (transition: all di tombol malam = 6 event), gak datang tanpa perubahan atau saat display: none (itu transitioncancel).

Yang akan kamu pelajari