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ử?

ease-out
spring

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ốngNên dùngLý do
Toggle switch thumbSpringVật lý, có trọng lượng
Modal backdrop fadeEaseKhông có khối lượng
Like button scaleSpringPhản hồi trực tiếp từ tap
Page transitionEaseChuyển cảnh, không phải vật thể
Bottom sheet slide upSpringDirect manipulation
Tooltip appearEaseXuất hiện, không di chuyển
Drag-and-drop dropSpringVật thể rơi xuống
Skeleton loader fadeEaseTrạ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ỗ.