SVG from Zero to Senior · Part 18 — Animation Libraries for SVG
When hand-rolled rAF and CSS stop scaling: what GSAP, anime.js, and Motion give you — timelines, stagger, scrubbing, MorphSVG, MotionPath — plus a decision table for CSS vs SMIL vs library. With a live timeline/stagger player.
In Part 6 you animated SVG by hand with CSS, SMIL, and requestAnimationFrame. {Ở Phần 6 con animate SVG bằng tay với CSS, SMIL, và requestAnimationFrame.} That covers most needs. {Cái đó bao phủ đa số nhu cầu.} But the moment you need orchestration — five things animating in a precise sequence, with stagger, that you can scrub and reverse — hand-rolling becomes a second job. {Nhưng khoảnh khắc con cần điều phối — năm thứ animate theo trình tự chính xác, có stagger, mà con tua và đảo được — tự code thành một công việc thứ hai.} That is the gap animation libraries fill. {Đó là khoảng trống các thư viện animation lấp.}
Play and scrub the staggered timeline, then change the stagger — this is the feature you’re really paying a library for. {Phát và tua timeline có stagger, rồi đổi stagger — đây là tính năng con thực sự trả tiền cho thư viện.}
Open the full demo {Mở demo đầy đủ}: /tools/svg-anim-libs-demo/.
The demo is vanilla JS (this blog ships no animation library) but it implements a real timeline with stagger, easing, and a scrubber — the exact features below. {Demo là vanilla JS (blog không ship thư viện animation) nhưng nó cài một timeline thật với stagger, easing, và thanh tua — đúng các tính năng dưới đây.}
What you’re actually paying for: the timeline {Cái con thực sự trả tiền: timeline}
A single animation is easy. {Một animation đơn lẻ thì dễ.} A timeline — many tweens positioned in time, that you can pause, seek, reverse, speed up, and nest — is hard to build well. {Một timeline — nhiều tween đặt theo thời gian, mà con tạm dừng, tua, đảo, tăng tốc, và lồng nhau được — khó dựng cho tốt.} GSAP’s headline API: {API tiêu biểu của GSAP:}
const tl = gsap.timeline();
tl.from('.bar', {
scaleY: 0,
transformOrigin: 'bottom',
opacity: 0,
duration: 0.5,
ease: 'back.out(1.7)',
stagger: 0.09, // each element starts 90ms after the previous
});
tl.pause(); // full transport control...
tl.seek(0.5);
tl.reverse();
tl.timeScale(2);
stagger, seek, and reverse are the lines that would each take real code to reimplement correctly — and that’s before easing curves, units handling, and cross-browser quirks. {stagger, seek, và reverse là những dòng mà tự cài lại đúng mỗi cái tốn code thật — và đó là trước cả đường easing, xử lý đơn vị, và quirk trình duyệt.}
The contenders {Các ứng viên}
GSAP {GSAP}
The industry standard for complex web animation. {Chuẩn ngành cho animation web phức tạp.} Best-in-class timelines, plus SVG-specific plugins: MorphSVGPlugin (the robust morphing from Part 11, with auto point-matching), MotionPathPlugin (motion along a path), DrawSVGPlugin (line-drawing). {Timeline tốt nhất, cùng plugin riêng cho SVG: MorphSVGPlugin (morph chắc chắn từ Phần 11, tự khớp điểm), MotionPathPlugin, DrawSVGPlugin.} Reach for it for production-grade, sequenced, interactive motion. {Dùng cho chuyển động tầm production, có trình tự, tương tác.}
anime.js {anime.js}
Lightweight, with timelines, staggers, and SVG line-drawing/morph helpers built in. {Nhẹ, có timeline, stagger, và helper vẽ đường/morph SVG sẵn.} A great middle ground when you want GSAP-like ergonomics with a smaller bundle. {Điểm trung gian tốt khi con muốn trải nghiệm kiểu GSAP với bundle nhỏ hơn.}
Motion (formerly Framer Motion) {Motion (trước là Framer Motion)}
Declarative, spring-physics-based, and component-first — especially in React. {Khai báo, dựa trên vật lý lò xo, và component-first — đặc biệt trong React.} Animate SVG via motion.path, motion.circle, etc., with animate/transition props and gesture support. {Animate SVG qua motion.path, motion.circle,… với props animate/transition và hỗ trợ gesture.} Reach for it when motion is part of your component model. {Dùng khi chuyển động là một phần mô hình component.}
The decision table {Bảng quyết định}
| Tool | Best at | Reach for it when |
|---|---|---|
| CSS / WAAPI | transitions, hovers, loaders {transition, hover, loader} | one-shot motion, smallest footprint {chuyển động một lần, footprint nhỏ nhất} |
| SMIL | portable icon animation {animation icon chuyển giao được} | motion must live in the .svg file {chuyển động phải nằm trong file .svg} |
| GSAP | timelines, scrub, MorphSVG, MotionPath {timeline, tua, MorphSVG, MotionPath} | sequenced, interactive production motion {chuyển động production có trình tự, tương tác} |
| anime.js | lightweight timelines & staggers {timeline & stagger nhẹ} | GSAP-like with a smaller bundle {kiểu GSAP với bundle nhỏ hơn} |
| Motion | spring physics, component/React motion {vật lý lò xo, chuyển động component/React} | declarative component animation, gestures {animation component khai báo, gesture} |
When NOT to add a library {Khi nào KHÔNG thêm thư viện}
A senior pushes back on dependencies. {Senior cân nhắc kỹ phụ thuộc.} Don’t ship 30–70 KB of animation library for: {Đừng ship 30–70 KB thư viện animation cho:} a spinner (CSS), a hover lift (CSS transition), a single line-drawing (Part 6’s stroke-dashoffset + CSS), or one self-contained animated icon (SMIL). {một spinner (CSS), nhấc khi hover (transition CSS), một lần vẽ đường (stroke-dashoffset Phần 6 + CSS), hay một icon động độc lập (SMIL).} Add the library when the orchestration — sequencing, stagger, scrub, complex morph — would otherwise be more code (and more bugs) than the dependency. {Thêm thư viện khi điều phối — trình tự, stagger, tua, morph phức tạp — sẽ tốn nhiều code (và nhiều lỗi) hơn cả phụ thuộc.}
The master’s warnings {Lời cảnh báo của sư phụ}
- Don’t reach for a library to spin a loader. That’s a one-line CSS animation. {Đừng dùng thư viện để quay một loader. Đó là animation CSS một dòng.}
- Animate
transform/opacityeven with a library — they composite on the GPU; libraries don’t change physics. {Animatetransform/opacityngay cả với thư viện — chúng composite trên GPU; thư viện không đổi vật lý.} - Respect
prefers-reduced-motion— every library lets you gate or shorten animations; do it. {Tôn trọngprefers-reduced-motion— mọi thư viện cho con chặn hoặc rút ngắn animation; hãy làm.}
Practice, or it didn’t happen {Luyện tập, không thì coi như chưa học}
- Hand-roll a stagger {Tự code một stagger}: reveal a row of bars with
--index-based CSS delays — feel why timelines exist. {lộ một hàng cột với delay CSS theo--index— cảm nhận vì sao timeline tồn tại.} - Same thing in a library {Việc đó trong thư viện}: rebuild it with anime.js or GSAP
staggerand compare the code. {dựng lại bằngstaggercủa anime.js hoặc GSAP và so code.} - Scrubbable timeline {Timeline tua được}: wire a range input to a paused timeline’s
seek()(or your ownapplyAt(t)). {nối một range input vớiseek()của timeline đang dừng (hoặcapplyAt(t)của con).}
What’s next {Phần tiếp theo}
You now know when motion deserves a dependency. {Giờ con biết khi nào chuyển động đáng có một phụ thuộc.} Next we go under the hood. {Tiếp theo ta chui xuống gầm máy.} In Part 19 we study SVG performance and rendering internals — how the browser paints SVG, why thousands of nodes get slow, the cost of filters and large paths, and the exact signals that tell you to switch to <canvas> or WebGL. {Ở Phần 19 ta nghiên cứu hiệu năng và nội tại render SVG — trình duyệt vẽ SVG thế nào, vì sao hàng nghìn node chậm, chi phí của filter và path lớn, và các tín hiệu chính xác báo con chuyển sang <canvas> hoặc WebGL.}