Gerak pada antarmuka membantu pengguna memahami perubahan, tetapi bagi sebagian orang justru menimbulkan pusing atau mual — misalnya pengguna dengan gangguan pada sistem keseimbangan (vestibular). Karena itu sistem operasi menyediakan pengaturan “kurangi gerakan”, dan CSS dapat membacanya melalui media query prefers-reduced-motion
. Menghormati preferensi tersebut bukan fitur tambahan: animasi kita harus tetap bermakna bagi pengguna yang memilih tanpa gerak. Pada Chapter ini kita menyusun pola media query yang wajib menyertai animasi, membiasakan pola pembungkus global, dan mengenal @starting-style untuk kemunculan halus yang tetap ramah gerak.
Media Query prefers-reduced-motion #
Pola dasarnya: tuliskan gaya beranimasi seperti biasa, lalu tulis ulang aturan yang bermasalah di dalam @media (prefers-reduced-motion: reduce). Media query ini punya dua nilai: no-preference untuk pengguna tanpa pengaturan khusus dan reduce untuk pengguna yang memilih mengurangi gerakan — pilihannya tersedia di pengaturan aksesibilitas sistem operasi, dan browser meneruskan pilihan tersebut ke halaman. Demo chapter ini memuat panel bergoyang, bola berputar, dan tombol bertransisi:
.panel-gerak {
transition-property: opacity;
transition-duration: 0.4s;
animation: goyang 1.6s ease-in-out infinite;
}
/* Hormati preferensi pengguna */
@media (prefers-reduced-motion: reduce) {
.panel-gerak {
animation: none;
transition-duration: 0.01ms;
}
.bola {
animation-duration: 0.01ms;
animation-iteration-count: 1;
}
.tombol {
transition-duration: 0.01ms;
}
}Mari kita telaah keputusan-keputusannya:
- Baris 1–5 (gaya dasar): panel beranimasi penuh — inilah keadaan bagi pengguna yang tidak mengubah pengaturan apa pun.
- Baris 9–10 (
animation: none): gerakan bolak-balik dihilangkan seluruhnya bagi pengguna reduce, sebab gerakan berulang adalah jenis gerak yang paling mengganggu. - Baris 11 (
transition-duration: 0.01ms): transisi dipendekkan hingga nyaris nol, tetapi tidak sampai nol. Durasi 0,01ms menjaga eventtransitionenddananimationendtetap terpicu, sehingga kode JavaScript yang menunggu event tersebut tidak macet. - Baris 12–14 (
0.01ms+iteration-count: 1): bola berhenti setelah satu siklus sekejap; animasi tidak berulang tanpa henti. - Baris 15–17: perubahan warna tombol tetap diizinkan, hanya dibuat seketika — umpan balik warna tidak memicu gangguan gerak.
Hasil di Browser:
Headless browser pengujian memakai preferensi bawaan (no-preference),
sehingga gaya dasar yang diperiksa harness: panel → animation-name
"goyang", animation-duration "1.6s", transition-property "opacity",
transition-duration "0.4s"; bola → animation-name "putar", duration
"2.4s"; tombol → transition-duration "0.2s" dengan background
"rgb(124, 58, 237)". Pada perangkat pengguna reduce, blok media query
mematikan animasi panel dan bola serta memendekkan semua transisi.Pola Pembungkus Global #
Menulis ulang setiap animasi satu per satu memakan waktu pada proyek besar. Pola pembungkus global berikut membatalkan seluruh gerakan sekaligus dengan satu aturan:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}Pola ini menonaktifkan smooth scroll juga lewat scroll-behavior: auto. Penggunaan !important di sini adalah pengecualian yang wajar — media query ini memang harus menimpa semua aturan animasi dari mana pun asalnya. Meski begitu, pendekatan targeted pada bagian sebelumnya tetap lebih baik untuk komponen penting: pembungkus global dapat memengaruhi animasi yang justru bermakna, misalnya indikator progres yang sedang berjalan.
Ketika memeriksa hasil, gunakan panel Rendering di DevTools dan aktifkan opsi emulasi prefers-reduced-motion. Dengan begitu kita dapat melihat halaman dari dua sudut pandang — dengan dan tanpa gerakan — tanpa mengubah pengaturan sistem operasi.
Sasaran yang perlu ditinjau saat mengaudit gerak: animasi besar yang menggerakkan seluruh bagian halaman (parallax, auto-scrolling), animasi berulang tanpa henti, dan blink yang cepat. Umpan balik kecil seperti crossfade opacity pendek umumnya aman dipertahankan.
@starting-style untuk Kemunculan Halus #
Elemen yang baru ditambahkan ke DOM tidak punya “keadaan sebelumnya”, sehingga transition biasa tidak berjalan — elemen muncul mendadak. @starting-style , yang merupakan Baseline sejak 2024, memberi titik awal transisi untuk render pertama:
.toast {
opacity: 1;
transform: translateY(0);
transition: opacity 0.3s ease, transform 0.3s ease;
}
@starting-style {
.toast {
opacity: 0;
transform: translateY(12px);
}
}Dengan aturan di atas, toast yang baru dirender naik dari bawah secara halus. Bagi pengguna reduce, pola ini tetap aman: transisinya dipendekkan menjadi 0,01ms sehingga toast tampil seketika tanpa gerakan. Pemakaian lengkapnya — termasuk kombinasi dengan transition-behavior: allow-discrete untuk elemen display: none — kita praktikkan pada Chapter Interaction Feedback
.