Foundations
Motion
Chuyển động ngắn và có lý do: cho biết thứ gì vừa xuất hiện, từ đâu tới và đi đâu. Vào chậm dần, ra nhanh dần.
Token
Bấm ▶ để chạy. Minh hoạ thời lượng chậm ×4 để dễ quan sát.
durationUltraFast
duration-ultra-fast · 50ms
Phản hồi tức thì (nhấn)
durationFaster
duration-faster · 100ms
Hover, đổi màu, icon
durationFast
duration-fast · 150ms
Bề mặt rời đi
durationNormal
duration-normal · 200ms
Mở / đóng nội dung tại chỗ
durationGentle
duration-gentle · 250ms
Bề mặt đi vào (Dialog, Drawer)
durationSlow
duration-slow · 300ms
Chuyển động lớn, hiếm
curveDecelerateMid
ease-decelerate-mid
Phần tử đi vào
curveAccelerateMid
ease-accelerate-mid
Phần tử rời đi
curveEasyEase
ease-easy-ease
Đổi trạng thái tại chỗ
curveDecelerateMax
ease-decelerate-max
Đi vào, quãng dài
curveAccelerateMax
ease-accelerate-max
Rời đi, quãng dài
curveEasyEaseMax
ease-easy-ease-max
Đổi chỗ trên màn hình
curveLinear
ease-linear
Progress, xoay vòng
Utility & keyframe
duration-* đặt transition-duration, ease-* đặt transition-timing-function. Các animate-* dưới đây có sẵn trong theme (theme.css, theme-core.css); keyframe nằm trong @theme nên Tailwind chỉ xuất keyframe mà một class hay khai báo animation dùng tới. Muốn thay một keyframe bằng @keyframes cùng tên của app, khai báo nó trong @theme.
| Utility | Chuyển động | Thời lượng · đường cong |
|---|---|---|
animate-fade-in | opacity 0 → 1 | 200ms · decelerate-mid |
animate-fade-out | opacity 1 → 0 | 150ms · accelerate-mid |
animate-surface-in | opacity 0 → 1, scale 0.96 → 1 | 250ms · decelerate-mid |
animate-surface-out | opacity 1 → 0 | 150ms · accelerate-mid |
animate-slide-in-start / -end / -bottom | trượt vào từ mép đầu / cuối / đáy (lật theo RTL) | 250ms · decelerate-mid |
animate-slide-out-start / -end / -bottom | trượt ra về mép đó | 150ms · accelerate-mid |
animate-sweep | dải sáng chạy ngang, bằng transform (Skeleton) | 1.8s · linear · ∞ |
animate-indeterminate-slide | thanh 1/3 chạy ngang, bằng transform (ProgressBar không xác định) | 3s · linear · ∞ |
animate-shimmer / animate-indeterminate | bản cũ đổi background-position / left (vẽ lại mỗi frame) | 1.8s / 3s · linear · ∞ |
Theo component
Cặp vào / ra mà mỗi component dùng, kèm component thật. Bật xem trước để thấy chúng khi người dùng chọn giảm chuyển động.
Dialog
- Vào
- surface-in 250ms · fade-in (backdrop)
- Ra
- fade-out 150ms
- Giảm
- Giữ nguyên: chỉ mờ và thu nhỏ 4%.
Drawer / Sheet
- Vào
- slide-in-start | end | bottom 250ms
- Ra
- slide-out-* 150ms
- Giảm
- Không trượt: hiện và ẩn ngay; nền phủ vẫn mờ dần.
Menu / Popover
- Vào
- surface-in 250ms
- Ra
- fade-out 150ms
- Giảm
- Giữ nguyên.
Tooltip
- Vào
- fade-in 200ms
- Ra
- fade-out 150ms
- Giảm
- Giữ nguyên.
Toast
- Vào
- slide-in-end (góc cuối) · surface-in (giữa)
- Ra
- slide-out-end · vuốt để đóng
- Giảm
- Không trượt: hiện và ẩn ngay.
Accordion
- Vào
- grid-template-rows 200ms · easy-ease
- Ra
- grid-template-rows 200ms · easy-ease
- Giảm
- Mở / đóng ngay, chevron không xoay.
Tabs
- Vào
- màu vạch chỉ báo 100ms · easy-ease
- Ra
- không trượt giữa các tab
- Giảm
- Giữ nguyên (chỉ đổi màu).
Playground
Chọn thuộc tính, rồi thời lượng và đường cong cho hai phương án; chạy để so sánh và chép class.
A
B
/* A */ transition-[translate] duration-gentle ease-decelerate-mid
/* B */ transition-[translate] duration-gentle ease-linearGiảm chuyển động
Khi hệ điều hành bật prefers-reduced-motion, component bỏ trượt, xoay và vòng lặp; mờ dần ngắn vẫn giữ để thấy được thay đổi.
| Component | Khi giảm chuyển động |
|---|---|
| Drawer, Sheet, Toast | Không trượt; nền phủ vẫn mờ dần. |
| Accordion, Collapse, Fade, Slide, Scale | Đổi trạng thái ngay. |
| Carousel | Không tự chạy, chuyển slide không cuộn mượt. |
| Skeleton, ProgressBar, Spinner, Chart | Không chạy vòng lặp hay hiệu ứng vẽ. |
| Stagger, Tour | Hiện cùng lúc, không lần lượt. |
| Dialog, Menu, Popover, Tooltip | Giữ nguyên: mờ dần 150–250ms, không di chuyển. |
Công tắc ở phần Theo component áp đúng các class motion-reduce:* mà component khai báo. Hành vi viết bằng JavaScript (Carousel, Stagger, Tour) chỉ đổi khi bật thật trong hệ điều hành hoặc trong DevTools (Rendering › Emulate CSS media feature prefers-reduced-motion).
Khi tự viết chuyển động, thêm motion-reduce:transition-none hoặc motion-reduce:animate-none ngay cạnh class chuyển động.
Phối hợp
Nhiều thứ cùng đổi thì cho chúng đi theo một thứ tự, cùng một hướng. Chỉ animate khi chuyển động giúp người dùng theo kịp thay đổi.
Danh sách lần lượt
Stagger: cách nhau 100ms, ẩn theo thứ tự ngược lại.
- Hộp thư
- Bản nháp
- Đã gửi
- Lưu trữ
Khung xương → nội dung
Fade tại chỗ, không trượt.
Bố cục thay đổi
Collapse / Accordion đẩy nội dung bên dưới cùng nhịp.
- Chuyển trang trong docs và trong app: không animate cả trang; thanh PageProgress là đủ.
- Không animate khi dữ liệu cập nhật liên tục (bảng, log, chat đang stream).
- Bề mặt mở ra từ nút bấm thì xuất hiện cạnh nút đó (Menu, Popover).
Hiệu năng
- Animate
transform/translate/scalevàopacity: trình duyệt chạy chúng trên compositor, không tính lại bố cục. - Tránh animate
width,height,top,left,margin. Accordion và Collapse là ngoại lệ có chủ ý: vùng nhỏ, 200ms, dùng grid-template-rows. will-changechỉ đặt ngay trước chuyển động và bỏ sau đó; đặt lâu dài tốn bộ nhớ GPU.- Chuyển động chạy lâu (shimmer, indeterminate) dùng CSS animation thay vì requestAnimationFrame, để không chiếm luồng chính.
Nên & không nên
- Ra nhanh hơn vào (ra 150ms, vào 250ms).
- Trượt từ mép mà bề mặt gắn vào, và lật theo RTL.
- Dùng token duration-* và ease-* để chuyển động đồng nhất.
- Nảy hay vượt đích trên khung giao diện.
- Animate mỗi lần hover hay mỗi lần dữ liệu cập nhật.
- Quá 300ms cho thứ người dùng phải chờ.