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:

css reduced-motion.html (cuplikan)
.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:

  1. Baris 1–5 (gaya dasar): panel beranimasi penuh — inilah keadaan bagi pengguna yang tidak mengubah pengaturan apa pun.
  2. Baris 9–10 (animation: none): gerakan bolak-balik dihilangkan seluruhnya bagi pengguna reduce, sebab gerakan berulang adalah jenis gerak yang paling mengganggu.
  3. Baris 11 (transition-duration: 0.01ms): transisi dipendekkan hingga nyaris nol, tetapi tidak sampai nol. Durasi 0,01ms menjaga event transitionend dan animationend tetap terpicu, sehingga kode JavaScript yang menunggu event tersebut tidak macet.
  4. Baris 12–14 (0.01ms + iteration-count: 1): bola berhenti setelah satu siklus sekejap; animasi tidak berulang tanpa henti.
  5. Baris 15–17: perubahan warna tombol tetap diizinkan, hanya dibuat seketika — umpan balik warna tidak memicu gangguan gerak.

Hasil di Browser:

text
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:

css
@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:

css
.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 .