Animation CSS qua một ví dụ
Một animation gồm hai phần: @keyframes mô tả các bước, và thuộc tính animation áp dụng các bước đó cho phần tử với một thời lượng. Tấm thẻ này trượt vào và hiện dần khi trang tải xong:
Sửa code (hoặc đổi thời lượng thành 2s) là bản xem trước tải lại, để bạn xem tấm thẻ trượt vào thêm lần nữa. Khối @media (prefers-reduced-motion: reduce) thay keyframes bằng hiệu ứng hiện dần, chỉ dành cho người đọc có hệ thống được đặt chế độ giảm chuyển động.
Cú pháp @keyframes
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.08); }
100% { transform: scale(1); }
}
fromtương đương0%vàtotương đương100%.- Thêm bao nhiêu bước phần trăm tùy ý. Các bước có cùng style có thể viết chung một dòng:
0%, 100% { ... }. - Thuộc tính nào thiếu ở keyframe đầu hoặc cuối sẽ chuyển động từ hoặc về giá trị gốc của phần tử.
- Tên (
pulse) là giá trị bạn truyền vàoanimation-name. Tên phân biệt chữ hoa chữ thường và không được trùng từ khóa nhưnone.
Các thuộc tính animation
| Thuộc tính | Đặt gì | Mặc định |
|---|---|---|
animation-name | @keyframes nào sẽ chạy | none |
animation-duration | độ dài một chu kỳ | 0s |
animation-timing-function | đường cong tốc độ giữa các keyframe | ease |
animation-delay | thời gian chờ trước chu kỳ đầu (giá trị âm bắt đầu từ giữa chừng) | 0s |
animation-iteration-count | số chu kỳ, hoặc infinite | 1 |
animation-direction | normal, reverse, alternate, alternate-reverse | normal |
animation-fill-mode | style trước và sau: none, forwards, backwards, both | none |
animation-play-state | running hoặc paused | running |
Cách viết rút gọn nhận các giá trị theo gần như mọi thứ tự. Quy tắc duy nhất: giá trị thời gian đầu tiên là thời lượng, giá trị thứ hai là thời gian chờ:
.loader {
animation: pulse 1.2s ease-in-out 0.2s infinite alternate both;
/* name duration timing delay count direction fill */
}
direction và fill-mode, xem trực tiếp
Chọn hướng, fill mode và số lần, rồi nhấn Play. Chiếc hộp di chuyển 200px đến cuối đường chạy. Dòng kết quả cho biết nó dừng ở đâu sau khi animation kết thúc:
Những điều cần để ý:
fill-mode: none(mặc định): sau khung hình cuối, hộp nhảy về x = 0 và trở lại màu hổ phách.forwards: hộp giữ nguyên ở keyframe cuối. Vớinormalđó là x = 200 và màu xanh lá; vớireversehộp dừng ở x = 0 và màu xanh dương, vì keyframe chạy sau cùng làfrom.alternatevới số lần là 2 sẽ đi rồi về, nên ngay cảforwardscũng dừng ở x = 0.
Lặp vô hạn: hiệu ứng loading
infinite lặp mãi mãi, và animation-delay trên từng phần tử con làm chúng lệch nhau để lần lượt chuyển động. Giữ vòng lặp nhẹ nhàng: chậm, nhỏ, không nhấp nháy.
role="status" cùng aria-label cho người dùng trình đọc màn hình biết có thứ đang tải, điều mà riêng các dấu chấm không nói được. Với vòng tròn xoay, xem trang rotate.
Tạm dừng và điều khiển animation
animation-play-state: paused đóng băng animation ngay tại chỗ, và running cho nó chạy tiếp từ đó. Di chuột lên thanh bên dưới để tạm dừng:
Từ JavaScript, element.getAnimations() trả về các animation CSS đang chạy, mỗi cái có pause(), play(), cancel() và currentTime để đọc hoặc đặt. Sự kiện animationend được kích hoạt khi một animation không lặp vô hạn kết thúc, còn animationiteration ở cuối mỗi chu kỳ.
Tôn trọng giảm chuyển động và không bao giờ nhấp nháy
Có hai quy tắc trợ năng áp dụng cho mọi animation:
- Giảm chuyển động. Có người yêu cầu hệ thống giảm chuyển động vì chuyển động làm họ khó chịu. Cách an toàn nhất là chỉ thêm chuyển động khi họ không yêu cầu giảm:
@media (prefers-reduced-motion: no-preference) {
.hero-title { animation: slide-in 0.8s ease-out both; }
}
- Không nhấp nháy. Nội dung nhấp nháy quá ba lần trong một giây có thể gây co giật. Hãy tránh hoàn toàn kiểu nhấp nháy nhanh, tương phản cao.
Giữ animation mượt
Hãy tạo animation cho transform và opacity khi có thể. Trình duyệt áp dụng được chúng mà không phải dàn trang lại, nên chúng vẫn mượt ngay cả trên điện thoại chậm. Tạo animation cho width, height, top, left hoặc margin sẽ tính lại bố cục ở mỗi khung hình. Để di chuyển phần tử, dùng translate() trong trang transform.
Lỗi thường gặp
- Không có thời lượng.
animation: fade;không làm gì cả, vì thời lượng mặc định là0s. - Tên không khớp.
animation-namephải khớp chính xác tên@keyframes, kể cả chữ hoa chữ thường. - Nhảy về lúc kết thúc. Thêm
forwards(hoặcboth) để giữ keyframe cuối. - Chớp hình trước khi animation có delay bắt đầu. Trong thời gian
animation-delay, phần tử hiển thị style bình thường.backwards(hoặcboth) áp dụng keyframe đầu tiên trong thời gian chờ. - Khởi động lại animation bằng cách đặt cùng giá trị. Đặt lại đúng giá trị
animationcũ không có tác dụng. Hãy gỡ nó, ép trình duyệt reflow (el.offsetWidth), rồi đặt lại, như nút Play ở trên làm. - Tạo animation cho
display. Thuộc tính này chuyển đổi ngay lập tức. Hãy tạo animation choopacityvàtransform.
Câu hỏi thường gặp
Làm sao tạo animation trong CSS?
Định nghĩa các bước bằng @keyframes name { from { ... } to { ... } }, rồi áp dụng cho một phần tử bằng thuộc tính animation kèm thời lượng: animation: name 1s ease-out;. Thời lượng là bắt buộc, vì giá trị mặc định của nó là 0s.
animation-fill-mode: forwards dùng để làm gì?
Nó giữ lại style của keyframe cuối cùng sau khi animation kết thúc. Nếu không có nó, phần tử sẽ nhảy về style bình thường. backwards áp dụng keyframe đầu tiên trong thời gian chờ (delay), còn both làm cả hai.
Làm sao cho animation CSS lặp vô hạn?
Đặt animation-iteration-count: infinite, hoặc thêm infinite vào cách viết rút gọn: animation: spin 1s linear infinite;. Thêm alternate để mỗi chu kỳ chạy xuôi rồi chạy ngược.
Animation và transition trong CSS khác nhau thế nào?
Transition tạo chuyển động cho một thuộc tính giữa hai giá trị khi nó thay đổi, thường là khi hover hoặc khi đổi class. Animation tự chạy ngay khi được áp dụng, có thể có bao nhiêu keyframe cũng được, và có thể lặp lại, chạy ngược và tạm dừng.
Làm sao tạm dừng animation CSS?
Đặt animation-play-state: paused cho phần tử, ví dụ trong :hover hoặc qua một class được JavaScript thêm vào. Đặt lại thành running thì animation chạy tiếp từ chỗ đã dừng.
Làm sao tắt animation cho người dùng muốn giảm chuyển động?
Bọc animation trong @media (prefers-reduced-motion: no-preference) { ... }, hoặc gỡ nó bên trong @media (prefers-reduced-motion: reduce) { ... }. Truy vấn này theo cài đặt giảm chuyển động trong hệ điều hành của người dùng.