Ease vs Spring: hai ngôn ngữ chuyển động
Khi thiết kế motion, câu hỏi thường gặp nhất là: “dùng easing gì cho phần này?” Câu trả lời đúng phụ thuộc vào một điều duy nhất — thứ đang di chuyển là vật lý hay điện tử?
Click Play để chạy cả hai đồng thời
Ease — chuyển động điện tử
Ease là hàm toán học. ease-out được định nghĩa bằng cubic-bezier với các control point nằm trong khoảng [0, 1] — nghĩa là giá trị output không bao giờ vượt ra ngoài phạm vi start–end.
/* Các preset phổ biến */
ease-in: cubic-bezier(0.42, 0, 1, 1)
ease-out: cubic-bezier(0, 0, 0.58, 1)
ease-in-out: cubic-bezier(0.42, 0, 0.58, 1)
Hành vi: bắt đầu, tăng tốc hoặc giảm tốc theo curve, dừng chính xác tại đích. Không có gì xảy ra sau khi đến nơi.
Dùng khi nào: UI elements không có trọng lượng vật lý — fade in/out, opacity change, color transition, page transition. Những thứ “xuất hiện” hoặc “biến mất” chứ không “di chuyển”.
Spring — chuyển động vật lý
Spring mô phỏng vật lý thực: một vật có khối lượng gắn vào lò xo. Khi bị kéo và thả ra, nó đi về điểm cân bằng nhưng mang theo quán tính — vượt qua đích, nảy lại, dao động quanh điểm cân bằng rồi mới dừng hẳn.
Trong CSS, spring được gần đúng bằng cubic-bezier có control point y > 1:
/* Spring — control point 1.56 tạo overshoot ~17% */
cubic-bezier(0.34, 1.56, 0.64, 1)
Giá trị y = 1.56 khiến output vượt quá 1.0 (tức là vượt qua endpoint) rồi quay về 1.0 để settle.
Dùng khi nào: Elements có “trọng lượng” hoặc phản hồi direct manipulation — toggle thumb, like button, popup, drawer, toast. Những thứ người dùng “đẩy”, “kéo”, hoặc “nhấn”.
Tại sao sự khác biệt quan trọng
Overshoot trong spring không phải lỗi — nó là tín hiệu vật lý. Khi toggle thumb nảy nhẹ qua điểm dừng, não người dùng nhận ra: “thứ này có khối lượng, nó thật”. Đây là lý do các UI vật lý (iOS toggle, Android bottom sheet) dùng spring còn các UI số (modal backdrop, tooltip) dùng ease.
Ngược lại, dùng spring cho những thứ không nên có trọng lượng (ví dụ: fade overlay, loading state) tạo ra cảm giác kỳ lạ — như thể bóng tối đang “nảy”.
Bảng tham khảo nhanh
| Tình huống | Nên dùng | Lý do |
|---|---|---|
| Toggle switch thumb | Spring | Vật lý, có trọng lượng |
| Modal backdrop fade | Ease | Không có khối lượng |
| Like button scale | Spring | Phản hồi trực tiếp từ tap |
| Page transition | Ease | Chuyển cảnh, không phải vật thể |
| Bottom sheet slide up | Spring | Direct manipulation |
| Tooltip appear | Ease | Xuất hiện, không di chuyển |
| Drag-and-drop drop | Spring | Vật thể rơi xuống |
| Skeleton loader fade | Ease | Trạng thái loading, không vật lý |
Cùng một duration, hai kết quả khác nhau
Cả hai animation trong demo đều chạy 0.7 giây với cùng điểm xuất phát và đích đến. Sự khác biệt nằm hoàn toàn ở đường đi — ease đi thẳng (toán học), spring vòng qua rồi quay lại (vật lý).
Duration dài không tự động tạo ra “feel” tốt hơn. Spring 0.3s thường tốt hơn ease 0.8s nếu đặt đúng chỗ.