CSS Keyframes — Web Animation

CSS Keyframes CSS Keyframes memungkinkan kamu membuat animasi multi-step yang lebih kompleks dari transition. Dengan keyframes, kamu bisa mendefinisikan state…

@keyframes adalah naskah sebuah animasi: daftar keadaan dengan tanda waktunya, dari 0% sampai 100%. Properti animation memutar naskah itu di satu elemen. Bayangin koreografi tari: gerakannya ditulis sekali dengan hitungan ("hitungan 1 tangan naik, hitungan 4 turun"), lalu tiap penari membawakannya dengan tempo, jumlah ulangan, dan arahnya sendiri. Bedanya dengan transition: transition butuh perubahan nilai untuk mulai dan cuma punya dua titik, sedangkan animation jalan sendiri begitu aturannya berlaku dan boleh punya banyak titik.

🧪 Tebakan cepat: Toast "Pesanan terkirim" punya gaya dasar opacity: 0 (tersembunyi). Saat muncul, dia diberi animation: toast-in 200ms ease-out, dan toast-in berakhir di opacity: 1. Setelah 200 ms, opacity-nya berapa? Jawabannya ada di bagian "fill-mode: apa yang tersisa setelah selesai".

Menulis @keyframes dan animation

@keyframes toast-in {
  from { opacity: 0; transform: translateY(120%); } /* sama dengan 0% */
  to   { opacity: 1; transform: none; }             /* sama dengan 100% */
}
.toast.show {
  animation: toast-in 200ms ease-out forwards;
}
Longhand Di toast Default
animation-name toast-in none
animation-duration 200ms 0s
animation-timing-function ease-out ease
animation-delay 0s 0s
animation-iteration-count 1 (angka, atau infinite) 1
animation-direction normal normal
animation-fill-mode forwards none
animation-play-state running running

Di latihan kamu merakit keduanya sebagai teks satu baris. Tiap langkah jadi persen% { properti: nilai; }, semua langkah digabung spasi, lalu dibungkus @keyframes nama { ... }:

Masukan Hasil
fadeIn, langkah 0 { opacity: 0 } dan 100 { opacity: 1 } @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } }
pop, langkah 0 { transform: "scale(1)", opacity: 0.5 } @keyframes pop { 0% { transform: scale(1); opacity: 0.5; } }
fadeIn, 0.5s, ease-out, 1 fadeIn 0.5s ease-out 1
spin, 1s, linear, infinite spin 1s linear infinite

Satu langkah boleh punya beberapa properti, dan pengulangan tanpa batas ditulis dengan kata infinite, bukan angka.

Titik di tengah: 0%, 50%, 100%

Naskah boleh punya titik di mana saja. Panah kecil "Lihat foto lain" di galeri Kamar Teras memantul tiga kali lalu diam:

@keyframes bounce {
  0%, 100% { transform: translateY(0); }   /* awal dan akhir di tempat */
  50%      { transform: translateY(-30px); } /* tengah: naik 30 px */
}
.hint { animation: bounce 600ms ease-in-out 3; }

fill-mode: apa yang tersisa setelah selesai

Animasi cuma menguasai nilainya selama dia jalan. Sebelum mulai dan setelah selesai, elemen kembali ke gaya dasarnya, kecuali animation-fill-mode bilang lain:

fill-mode Selama delay Setelah selesai
none gaya dasar gaya dasar
forwards gaya dasar nilai titik terakhir
backwards nilai titik pertama gaya dasar
both nilai titik pertama nilai titik terakhir

Toast tadi gaya dasarnya opacity: 0. Tanpa forwards, dia naik dan muncul selama 200 ms, lalu langsung kembali ke opacity: 0: hilang lagi. Itu jawaban tebakannya: 0. Kami mengujinya di Chromium 147, WebKit 26.4, dan Firefox 146: none berakhir di 0, forwards di 1. Untuk @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } dengan animation: fadeIn 2s forwards, opacity setelah selesai = 1, nilai to.

Toast lengkap: masuk, tunggu, keluar

Toast di halaman Bu Sri masuk 200 ms, tampil 5 detik dengan bar hitung mundur, lalu keluar 150 ms. Bar-nya berhenti selama penunjuk ada di atas toast, supaya orang sempat membaca.

.toast { opacity: 0; transform: translateY(120%); }        /* dasar: tersembunyi di bawah */
.toast.show { animation: toast-in 200ms ease-out forwards; }
.toast.hide { animation: toast-out 150ms ease-in forwards; }
.toast.show .bar, .toast.hide .bar {                       /* nama sama: bar gak mulai ulang saat keluar */
  transform-origin: left;
  animation: countdown 5s linear forwards;
}
.toast:hover .bar { animation-play-state: paused; }       /* bar berhenti selama dibaca */

@keyframes toast-in  { to { opacity: 1; transform: none; } }
@keyframes toast-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(120%); } }
@keyframes countdown { to { transform: scaleX(0); } }
@keyframes fade-in   { to { opacity: 1; } }
@keyframes fade-out  { from { opacity: 1; } to { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .toast { transform: none; }
  .toast.show { animation: fade-in 150ms linear forwards; }
  .toast.hide { animation: fade-out 150ms linear forwards; }
}
toast.addEventListener('animationend', (e) => {
  if (e.animationName === 'countdown') toast.className = 'toast hide'; // 5 detik habis
  if (e.animationName === 'toast-out') toast.hidden = true;            // sudah turun
});
Waktu Yang terjadi Event
0 ms kelas show: toast naik, bar mulai menyusut animationstart toast-in, animationstart countdown
200 ms toast sampai, tetap terlihat karena forwards animationend toast-in
5.000 ms bar habis animationend countdown, kelas jadi hide
5.150 ms toast sudah turun animationend toast-out, hidden = true

Ulangan, arah, dan event

⚠️ Jebakan yang sering ketemu

TL;DR: @keyframes nama { 0% { ... } 50% { ... } 100% { ... } } menulis naskah (from = 0%, to = 100%, satu titik boleh banyak properti, 0%, 100% boleh berbagi blok). animation: nama durasi easing ulangan memutarnya (fadeIn 0.5s ease-out 1, spin 1s linear infinite); waktu pertama durasi, kedua delay; easing berlaku per potongan. fill-mode: none kembali ke gaya dasar, forwards menahan titik terakhir (fadeIn 2s forwards berakhir di opacity 1), backwards memakai titik pertama selama delay, both keduanya. play-state: paused menghentikan waktunya. Event: animationstart, animationiteration per batas ulangan, animationend (gak datang untuk infinite), dan animationcancel saat display: none. Untuk memutar ulang: hapus kelas, paksa reflow, tambahkan lagi.

Yang akan kamu pelajari