Microinteractions & Animation — UI/UX

Microinteractions & Animation — Detail yang Bikin UI Terasa Hidup Microinteractions adalah animasi kecil yang memberi feedback saat user berinteraksi dengan…

Microinteraction adalah satu momen kecil di sekitar satu tugas: tombol yang sedikit mengecil saat ditekan, label yang berubah jadi "Memesan...", pesan kecil yang muncul lalu hilang sendiri. Animation adalah cara momen itu bergerak. Bayangin tombol lift. Kamu menekannya, lampunya langsung menyala (kamu tahu tekananmu diterima), liftnya datang, dan lampunya padam begitu pintu terbuka. Kalau lampunya gak menyala, kamu menekan tombol itu lima kali. Microinteraction di halaman Homestay Kabut adalah lampu tombol lift itu.

🧪 Tebakan cepat: Pak Hadi (58) menyalakan "Kurangi gerakan" di HP-nya. Tim Bu Sri menghormatinya dengan transition: none untuk semua elemen. Toast "Pesanan terkirim" pergi setelah 5 detik, dan kodenya menyembunyikan toast (toast.hidden = true) saat event transitionend datang. Toast-nya sudah gak terlihat. Sudah hilang juga dari pohon aksesibilitas, yang dibaca screen reader? Jawabannya ada di bagian "prefers-reduced-motion: gerakan dikurangi, bukan dibuang".

Empat bagian microinteraction

Dan Saffer, di bukunya Microinteractions: Designing with Details (O'Reilly, 2013), membagi tiap microinteraction jadi empat bagian: Trigger, Rules, Feedback, Loops & Modes. Ini tombol "Pesan kamar, bayar di tempat":

Bagian Artinya Di tombol Pesan
Trigger yang memulai: tindakan orang (manual trigger) atau keadaan sistem (system trigger) Pak Hadi mengetuk tombolnya; jawaban server memulai toast
Rules apa yang boleh terjadi dan urutannya tombol berpindah idle, hover, pressed; selama memesan, ketukan kedua diabaikan
Feedback cara orang tahu apa yang terjadi: gambar, suara, getaran tombol mengecil 2% saat ditekan, label "Memesan...", toast "Pesanan terkirim"
Loops & Modes apa yang terjadi seiring waktu (loop) dan cabang aturan (mode) toast hilang sendiri setelah 5 detik; mode "memesan" saat tombol gak menerima ketukan

Urutan bacanya: trigger memulai, rules menentukan, feedback memberi tahu, loops & modes mengatur sesudahnya.

Rules sebagai state machine

Rules tombol Pesan paling jelas ditulis sebagai state machine: daftar keadaan (state), dan event apa memindahkan dari keadaan mana ke mana. Event-nya adalah pointer event dari browser, yang sama untuk mouse, jari, dan pena.

const TRANSITIONS = {
  idle:    { pointerenter: 'hover' },                        // penunjuk masuk ke tombol
  hover:   { pointerdown: 'pressed', pointerleave: 'idle' }, // ditekan, atau penunjuk keluar
  pressed: { pointerup: 'hover', pointerleave: 'idle' },     // dilepas, atau digeser keluar
};

Jejak satu ketukan penuh, mulai dari idle:

Event Dari Jadi
pointerenter idle hover
pointerdown hover pressed
pointerup pressed hover
pointerleave hover idle

Tiap state punya tampilannya sendiri di CSS: hover warnanya lebih gelap (#166534), pressed mengecil scale(0.98). Di latihan nanti kamu menulis nextState(current, event) dan runSequence(events) dari tabel ini.

Durasi dan easing dalam angka

Page Laubheimer dari Nielsen Norman Group ("Executing UX Animations: Duration and Motion Characteristics", 2020): kebanyakan animasi UI sebaiknya 100 sampai 500 ms; feedback sederhana seperti checkbox atau toggle kira-kira 100 ms; perubahan besar seperti modal masuk 200 sampai 300 ms; di 500 ms animasi mulai terasa menyeret. Untuk hover dan tekan tombol, pakai 100 sampai 200 ms, tengahnya 150 ms.

.nights button { transition: transform 100ms ease-out, background-color 150ms ease-out; }
.nights button:active { transform: scale(0.96); }

.book { transition: transform 100ms ease-out, background-color 150ms ease-out; }
.book[data-state="hover"]   { background: #166534; }
.book[data-state="pressed"] { transform: scale(0.98); }

.toast { transform: translateY(120%); opacity: 0;
         transition: transform 150ms ease-in, opacity 150ms ease-in; }    /* keluar */
.toast.show { transform: none; opacity: 1;
              transition-duration: 200ms; transition-timing-function: ease-out; } /* masuk */

Easing adalah kurva kecepatan animasi. Kami menjalankan animasi 1 detik sejauh 100px dengan Web Animations API dan membaca posisinya di Chromium 147, WebKit 26.4, dan Firefox 146. Hasilnya sama di ketiganya:

Easing 25% waktu 50% waktu 75% waktu
linear 25px 50px 75px
ease-out 37,8px 68,5px 90,7px
ease-in 9,3px 31,5px 62,2px
ease-in-out 12,9px 50px 87,1px
cubic-bezier(0.34, 1.56, 0.64, 1) 81,6px 108,7px 106px

Animasikan transform dan opacity saja

Browser menggambar halaman dalam tiga langkah: layout (menghitung posisi dan ukuran), paint (mewarnai), composite (menyusun lapisan). transform dan opacity cukup di langkah composite. top, bottom, width, atau margin memaksa layout dihitung ulang di setiap frame.

Kami menganimasikan toast yang sama selama 200 ms di Chromium 147:

Toast naik lewat Layout dihitung ulang Layout shift
transform: translateY(...) 0 sampai 1 kali 0
bottom: -64px jadi 16px 23 sampai 24 kali 13 entri

Hasilnya terlihat sama di layar, tapi versi bottom menghitung ulang posisi seluruh halaman di hampir setiap frame, dan di HP murah itulah yang bikin animasi patah-patah. Mengganti background-color di tombol malam memicu paint, bukan layout (0 kali di tes kami), jadi masih ringan.

prefers-reduced-motion: gerakan dikurangi, bukan dibuang

Ada orang yang pusing atau mual melihat gerakan di layar (gangguan vestibular). Mereka menyalakan pengaturan sistem: "Kurangi gerakan" di iPhone dan Mac, "Hapus animasi" di Android, "Efek animasi" mati di Windows. Browser meneruskannya sebagai media query prefers-reduced-motion: reduce. WCAG 2.3.3 (Animation from Interactions, level AAA) meminta animasi yang dipicu interaksi bisa dimatikan.

Kami menyalakan reduce di Chromium, WebKit, dan Firefox, lalu memindahkan elemen yang punya transisi 200 ms:

Aturan di dalam @media (prefers-reduced-motion: reduce) transitionend
transition: none 0 kali
transition-duration: 0s 0 kali
transition-duration: 0.01ms 1 kali, setelah 1 sampai 16 ms

Jadi jawaban tebakannya: belum. Dengan transition: none, toast langsung jadi opacity: 0 dan pindah ke posisi sembunyinya, tapi transitionend gak pernah datang, jadi toast.hidden = true gak pernah jalan. Di Chromium 147, 7 detik setelah memesan, teks "Pesanan terkirim. Bu Sri akan konfirmasi lewat WhatsApp." masih ada di pohon aksesibilitas; dengan aturan fade di bawah, sudah hilang. Pengguna screen reader yang menelusuri halaman masih mendengar kabar lama itu seolah baru. Itu jawaban tebakannya.

Yang lebih baik: buang gerakannya, sisakan fade singkat.

@media (prefers-reduced-motion: reduce) {
  .toast, .toast.show {
    transform: none;                      /* gak meluncur */
    transition: opacity 150ms linear;     /* cuma memudar, transitionend tetap datang */
  }
  .nights button:active, .book[data-state="pressed"] { transform: none; }
}

⚠️ Jebakan yang sering ketemu

TL;DR: Microinteraction adalah satu momen kecil di sekitar satu tugas. Saffer (2013) membaginya jadi Trigger (yang memulai), Rules (apa yang boleh terjadi), Feedback (cara orang tahu), Loops & Modes (sesudahnya dan cabangnya). Rules tombol ditulis sebagai state machine: idle kena pointerenter jadi hover, pointerdown jadi pressed, pointerup kembali ke hover, pointerleave ke idle; event lain gak memindahkan apa pun. Durasi: feedback kecil 100 sampai 200 ms (sekitar 150), modal 200 sampai 300 ms, 500 ms mulai menyeret (NN/g 2020). Easing: ease-out untuk yang masuk, ease-in untuk yang keluar, linear untuk yang berputar. Animasikan transform dan opacity: di Chromium, toast lewat bottom menghitung layout 23 sampai 24 kali dalam 200 ms, lewat transform 0 sampai 1 kali. Hormati prefers-reduced-motion dengan fade singkat, bukan transition: none yang membuat transitionend gak pernah datang. Hal yang sering diulang: pendek, atau tanpa animasi.

Yang akan kamu pelajari