31 điểm bởi GN⁺ 2025-06-27 | 2 bình luận | Chia sẻ qua WhatsApp
  • 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 @keyframes hiệ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-range là 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/exit và 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

 
shakespeare 2025-06-29

Chỉ với animation-timeline thôi mà cũng có thể triển khai được nhỉ. Thật thú vị!

 
[Bình luận này đã bị ẩn.]