- Có thể triển khai animation đồng bộ theo cuộn trang chỉ với CSS mà không cần JS hay thư viện riêng
- Dùng các thuộc tính CSS như animation-timeline: scroll() / view() để cho animation chạy theo vị trí cuộn hoặc khi phần tử đi vào viewport
- Thuộc tính animation-range cho phép điều chỉnh chi tiết animation sẽ bắt đầu/kết thúc ở đoạn nào trong viewport
- Khuyến nghị dùng media query prefers-reduced-motion cho người dùng nhạy cảm với chuyển động
- Được hỗ trợ từ Safari 26 beta, mở rộng đáng kể phạm vi ứng dụng của animation cuộn trang dựa trên CSS
3 thành phần của animation dựa trên cuộn trang
- Target: phần tử đích được áp dụng animation (ví dụ: thanh tiến trình, hình ảnh, v.v.)
- Keyframes: định nghĩa những thay đổi sẽ xảy ra theo cuộn trang (giống với CSS
@keyframeshiện có) - Timeline: quyết định animation diễn ra khi nào và như thế nào (không dựa trên thời gian mà dựa trên cuộn trang/viewport)
Timeline trong CSS
- CSS animation truyền thống mặc định dùng document timeline (dựa trên thời gian)
- Sự xuất hiện của thuộc tính animation-timeline (CSS Animations Level 2, năm 2023) cho phép animation chạy theo nhiều tiêu chí ngoài thời gian như cuộn trang, đi vào viewport
scroll() timeline
- Timeline scroll() chỉ làm animation chạy khi người dùng cuộn trang
- Ví dụ: thanh tiến trình phía dưới tăng dần từ trái sang phải theo mức cuộn trang
footer::after { content: ""; height: 1em; width: 100%; background: rgba(254, 178, 16, 1); left: 0; bottom: 0; position: fixed; animation: grow-progress linear; animation-timeline: scroll(); } @keyframes grow-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } } - animation-timeline phải được khai báo sau thuộc tính animation thì mới hoạt động đúng
Cân nhắc về khả năng tiếp cận cho chuyển động
- Nên dùng media query prefers-reduced-motion để bảo vệ người dùng nhạy cảm với chuyển động
@media not (prefers-reduced-motion) { /* mã animation */ }
view() timeline
- Timeline view() bắt đầu animation khi phần tử đích xuất hiện trong viewport
- Ví dụ: khi cuộn trang, ảnh trượt từ phải sang và fade in
@keyframes slideIn { 0% { transform: translateX(100%); opacity: 0; } 100% { transform: translateX(0%); opacity: 1; } } img { animation: slideIn; animation-timeline: view(); }
Điều khiển phạm vi tiến trình bằng animation-range
-
Mặc định,
animation-rangelà 0% (đi vào viewport)~100% (rời khỏi hoàn toàn) -
Ví dụ: chỉ cho animation chạy đến 50% đoạn viewport
img { animation: slideIn; animation-timeline: view(); animation-range: 0% 50%; } -
Cần đặt giá trị range phù hợp để đảm bảo trải nghiệm người dùng
-
Khi cân nhắc khả năng tiếp cận cho chuyển động, hãy dùng cùng với prefers-reduced-motion
@media not (prefers-reduced-motion) { img { animation: slideIn; animation-timeline: view(); animation-range: 0% 50%; } }
Ứng dụng nâng cao và bước tiếp theo
scroll(),view()là các hàm, có thể chỉ định nhiều tùy chọn như phần tử scroller (mặc định: nearest) hoặc trục (block, inline, x, y)- Có thể tạo UX tinh tế hơn với
animation-range,entry/exitvà các tùy chọn liên quan - Hiện được hỗ trợ trước trên các trình duyệt mới như Safari 26 beta, và dự kiến sẽ dần được chuẩn hóa cũng như mở rộng hỗ trợ trong tương lai
2 bình luận
Chỉ với
animation-timelinethôi mà cũng có thể triển khai được nhỉ. Thật thú vị!