SVG from Zero to Senior · Part 24 — Scroll-Driven SVG Storytelling
Part 24: hand the timeline to the reader. Use the Scroll-driven Animations API (scroll() and view()) to draw an SVG path as the page scrolls, with parallax layers for depth and a JS fallback. With a live scrollytelling demo.
Mọi animation tới giờ chạy theo đồng hồ của nó. Scrollytelling lật điều đó: vị trí cuộn của người đọc trở thành timeline. Cuộn tới, chuyện diễn; cuộn lui, nó tua ngược. Đó là cách các bài giải thích và trang sản phẩm hay nhất trở nên sống động, và CSS hiện đại làm nó đơn giản đến bất ngờ.
Cuộn khung dưới: đường mòn vẽ ra, người leo núi đi lên, mặt trời mọc, và ba lớp parallax.
Mở demo đầy đủ:
Cách cũ và cách mới
Cách kinh điển là một listener scroll JS tính tiến trình 0→1 rồi cập nhật style. Nó chạy khắp nơi nhưng chạy JS trên main thread mỗi sự kiện cuộn. Cách mới là Scroll-driven Animations API — CSS thuần, chạy ngoài main thread:
#trail {
stroke-dasharray: var(--len);
stroke-dashoffset: var(--len);
animation: draw linear both;
animation-timeline: scroll(root); /* tie the animation to page scroll */
}
@keyframes draw { to { stroke-dashoffset: 0; } }
animation-timeline: scroll() thay thời gian bằng tiến trình cuộn. Không listener, không requestAnimationFrame, không giật.
scroll() và view()
Hai loại timeline bao phủ đa số nhu cầu:
- tiến trình trên toàn dải cuộn của một container. Tốt cho thanh tiến trình toàn cục hay câu chuyện trải dài bài.
- tiến trình khi một phần tử cụ thể băng qua viewport. Hoàn hảo cho “lộ biểu đồ này khi nó cuộn vào tầm nhìn.”
.reveal {
animation: fade-up linear both;
animation-timeline: view();
animation-range: entry 0% cover 40%; /* start as it enters, finish 40% in */
}
animation-range là núm điều khiển senior — nói phần nào hành trình qua viewport của phần tử ánh xạ vào 0→100%.
Vẽ-theo-cuộn: chiêu vẽ đường, được tua
Đây là vẽ đường của Phần 6, nhưng thay vì animation-duration điều khiển stroke-dashoffset, thì cuộn điều khiển. Đặt dash array bằng độ dài path, animate offset về 0, và buộc timeline vào cuộn — đường “tự viết” đúng nhịp người đọc.
Parallax = tốc độ dịch khác nhau
Chiều sâu là ảo giác dựng từ một sự thật: vật gần dịch nhiều hơn vật xa. Dịch mỗi lớp tỉ lệ với tiến trình cuộn, hệ số lớn hơn cho lớp gần hơn:
far.style.transform = `translateX(${-20 * p}px)`; // distant ridge — barely moves
mid.style.transform = `translateX(${-45 * p}px)`;
near.style.transform = `translateX(${-80 * p}px)`; // foreground — moves most
Luôn kèm fallback
CSS scroll-driven được hỗ trợ rộng nhưng chưa phổ quát. Khóa bản native sau @supports, và cung cấp bản JS-listener cho phần còn lại — demo làm đúng vậy.
const p = window.scrollY / (document.documentElement.scrollHeight - innerHeight);
trail.style.strokeDashoffset = len * (1 - p);
Lời cảnh báo của sư phụ
- Đừng chiếm scrollbar. Điều khiển hình ảnh bằng cuộn; đừng bẫy hay giả vị trí cuộn.
- Tiết chế fallback JS theo rAF.
- Tôn trọng
prefers-reduced-motion. - Giữ câu chuyện đọc được không cần hiệu ứng cuộn.
Thực hành
view()một biểu đồ: cho các cột Phần 20 mọc khi biểu đồ cuộn vào tầm nhìn.- Parallax hai tốc độ: thêm lớp sao dịch ngược đồi.
- Vòng tiến trình: điều khiển vòng tiến trình Phần 12 bằng
scroll(root).
Phần tiếp theo
Bạn đã trao chuyển động cho đồng hồ, không gian, bộ xương, và người đọc. Cho màn kết nhánh này, ta tạo chuyển động đơn giản sống — những cảnh nền lặp mãi. Ở Phần 25 ta dựng cảnh nền lặp & hạt — vòng lặp liền mạch, parallax trôi nhiều lớp, và một hệ hạt requestAnimationFrame nhẹ.