Motion-safe animations: Accessibility trong CSS animations
Không phải user nào cũng thoải mái với animations. prefers-reduced-motion và motion-safe strategies giúp bạn build inclusive animations mà vẫn đẹp.
Animations làm UI đẹp hơn, nhưng với một số người — vestibular disorders, motion sensitivity, migraine — animations gây chóng mặt, buồn nôn, thậm chí seizures. Là frontend dev, chúng ta có trách nhiệm build inclusive experiences.
prefers-reduced-motion
CSS media query prefers-reduced-motion detect OS-level accessibility setting. Users bật setting này trong System Preferences → Accessibility → Reduce Motion.
/* Approach 1: Reduce motion — opt-out */
/* Viết animations bình thường, rồi disable cho reduced-motion */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px oklch(0% 0 0 / 0.15);
}
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
.card:hover {
transform: none;
/* Giữ visual feedback nhưng không có motion */
box-shadow: 0 0 0 2px var(--primary);
}
}
/* Approach 2: Motion-safe — opt-in (recommended) */
/* Default là no animation, chỉ thêm cho users OK với motion */
.card {
/* No transition by default */
}
@media (prefers-reduced-motion: no-preference) {
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
}
}
Approach 2 (motion-safe / opt-in) an toàn hơn — nếu bạn quên handle một animation, nó đơn giản không chạy thay vì gây motion sickness.
Thực hành: Animation guidelines
Không phải mọi motion đều cần disable. Phân loại:
- Safe cho mọi user: opacity transitions, color changes, subtle shadows.
- Nên disable khi reduced-motion: parallax, large-scale movements, auto-playing animations, page transitions.
- Luôn cần cẩn thận: flashing content (>3 flashes/sec có thể gây seizure — WCAG violation).
Pattern cho component library
Trong design system, abstract motion decisions vào tokens:
:root {
--duration-fast: 150ms;
--duration-normal: 300ms;
--duration-slow: 500ms;
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
@media (prefers-reduced-motion: reduce) {
:root {
--duration-fast: 0ms;
--duration-normal: 0ms;
--duration-slow: 0ms;
}
}
/* Components dùng tokens — tự respect reduced-motion */
.modal {
transition: opacity var(--duration-normal) var(--ease-default),
transform var(--duration-normal) var(--ease-default);
}
.dropdown {
transition: opacity var(--duration-fast) var(--ease-default);
}
Bằng cách set duration về 0 cho reduced-motion, tất cả components tự động adapt mà không cần sửa từng component.
Testing
- Chrome DevTools: Rendering tab → Emulate CSS media feature → prefers-reduced-motion: reduce.
- macOS: System Settings → Accessibility → Display → Reduce motion.
- Thực tế: ~10-30% users bật reduced motion trên mobile. Không phải edge case.
Kết
Motion accessibility không khó — vài dòng CSS là đủ. Dùng motion-safe (opt-in) approach cho new projects, duration tokens cho design systems. Test bằng DevTools emulation. Accessible animations vẫn có thể đẹp — chúng chỉ cần thoughtful hơn.
Admin
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!