Making Graphics Move: Frontend Animation from CSS to WebGL
Static charts convey information. Animated charts convey process.
Many people think of “showing off” when they hear animations. But 95% of blog animation needs can be solved with CSS. CSS @keyframes + animation is like a Swiss Army knife — simple, reliable, no extra libraries, and respects user accessibility preferences through prefers-reduced-motion.
But there’s always that 5% where CSS falls short. Multi-element choreography, designer-created complex interactions, 3D data visualization, massive particle rendering. That’s when you need to find another path.
This post isn’t about “how to write animations” but “which path to choose.” CSS, GSAP, Lottie, Three.js, Canvas — how far can each road go, and where should you turn back.
SVG Animation: SMIL Isn’t Dead
SVG animation has three implementation paths: SMIL declarative animation, CSS-driven animation, and JavaScript-driven animation.
SMIL is SVG’s native animation mechanism with core elements:
<animate>: tween attributes<animateTransform>: animate transform properties (translate, rotate, scale, skew)<animateMotion>: move elements along paths
| |
In 2015, the Chrome team publicly proposed deprecating SMIL, citing high maintenance costs and functional overlap with the Web Animations API. But developers strongly opposed this — path morphing and SVG animations inside img tags have no CSS or Web Animations API equivalent. So Chrome paused the deprecation plan.
Need to clarify: SMIL hasn’t been “disabled” by modern browsers. All modern browsers (Chrome, Firefox, Safari, Edge) still support SMIL, only Internet Explorer never did. SVG 2 specification retains all animation elements.
The community generally recommends prioritizing CSS/JS animations for new projects because of better performance and integration with prefers-reduced-motion.
CSS-driven SVG animation typically outperforms SMIL and offers stronger control:
| |
SVG is DOM-based vector graphics. When elements get numerous, DOM operations become the bottleneck. Suitable for medium-scale graphics animation requiring accessibility and stylability — icon micro-interactions, loading animations, path drawing, data visualization transitions.
Author’s note: For Animated SVG in blogs, CSS animation is the best starting point. No extra libraries needed, better performance than SMIL, and controllable via prefers-reduced-motion. If complex choreography is needed, consider GSAP.
GSAP: Timeline is the Killer Abstraction
GSAP is developed by GreenSock and is one of the industry’s most mature JavaScript animation platforms.
v1.0 in 2010 standardized the API, introducing core concepts like timeline and easing functions. v3.0 in 2019 was a major update — file size halved from old TweenMax, simplified API, backward compatibility, timeline default value inheritance.
GSAP’s core is Tween and Timeline:
- Tween: Basic animation unit, defining start/end states via
gsap.to(),gsap.from(),gsap.fromTo(). Can operate any readable/writable property — not limited to CSS styles, but also direct SVG properties (viewBox, d path data, stroke-dasharray), Canvas context properties, etc. - Timeline: Chain/parallel orchestrate multiple tweens, precise control of timing, nesting, and overall playback control. This is GSAP’s killer abstraction.
| |
GSAP extends capabilities through plugins: MotionPathPlugin (path motion), ScrollTrigger (scroll-driven animation), MorphSVG (SVG shape morphing), DrawSVG (stroke drawing), Draggable, etc. Core library ~30KB, load on demand.
| Dimension | GSAP | CSS Animation |
|---|---|---|
| Strengths | Not limited to CSS-animatable properties, timeline orchestration far exceeds CSS, cross-browser consistency, rich easing functions | Zero dependency, declarative, browser native optimization |
| Weaknesses | Extra library size, requires JS execution | Complex choreography difficult, no fine-grained playback state control |
| Fit for | Complex choreography, scroll-driven, SVG morphing, data visualization transition animations | Simple state switching, hover effects, basic transitions |
Lottie: JavaScript Version of Designer Work
Lottie was open-sourced by Airbnb in 2017. It’s a cross-platform animation library (Android, iOS, Web, React Native, Windows) that parses JSON animations exported from Adobe After Effects via the Bodymovin plugin and renders natively on each platform.
Core workflow: Designer creates animation in After Effects → export to JSON via Bodymovin (or LottieFiles official plugin) → frontend uses lottie-web to parse and render.
Supports vector graphics, layers, masks, expressions, and other AE features. Provides Canvas / SVG / HTML three rendering modes.
Lottie is perfect for loading animations, empty state illustrations, and article decorative animations in blogs. You can find many free animation resources on the LottieFiles platform, import lottie-web, and play with a few lines of code.
| Dimension | Description |
|---|---|
| Use cases | UI animations, illustration animations, loading states, onboarding animations, empty state illustrations, micro-interactions |
| Strengths | Design-development decoupling, cross-platform consistency, vector scalability, small files, programmatic control |
| Weaknesses | Limited support for complex AE features, unsuitable for large-scale dynamic visualization, parsing overhead exists for complex JSON |
Lottie is essentially “designer-driven” fixed animation, not good at data-driven dynamic binding. In data visualization, it’s mainly used for decorative/state animations outside charts (like loading, success prompts), not the geometric mapping of data itself.
Three.js: 3D Visualization and Massive Data
Three.js is led by developer Ricardo Cabello (@mrdoob), an open-source 3D JavaScript library aiming to simplify WebGL’s complex low-level APIs.
Core abstractions: Scene (scene graph), Camera (camera), Renderer (renderer), Mesh (mesh = Geometry + Material), Light (lighting).
3D data visualization scenarios include: 3D scatter plots, point cloud visualization, earth visualization, molecular structure visualization, industrial equipment simulation, particle systems.
Uber’s open-source deck.gl is a large-scale data visualization framework based on WebGL, specifically designed for geospatial big data, providing high-performance layered rendering (points, arcs, grids, heatmaps, etc.).
kepler.gl is a web-based large-scale geospatial visualization application built on deck.gl that can render millions of points representing thousands of trips and perform real-time spatial aggregation.
| Dimension | Description |
|---|---|
| Use cases | True 3D space, massive data points (million-level), geospatial big data, immersive visualization |
| Strengths | GPU acceleration, strong expressiveness, can handle big data |
| Weaknesses | Steep learning curve, mobile/low-end device GPU compatibility needs attention, SEO and accessibility weaker than DOM/SVG |
Canvas Particle Systems: When Scale Trumps Everything
requestAnimationFrame is the browser’s native animation API, syncing draw calls with display refresh (typically 60Hz or 120Hz) and automatically pausing when tab is invisible to save CPU and battery.
The core idea of particle systems: maintain a list of tiny objects, each with position, size, color, speed, lifetime properties; each frame generates new particles, updates surviving particles, recycles dead particles, pushes data to GPU/Canvas.
| |
Performance optimization techniques include:
- Object pooling: reuse particle objects, avoid frequent GC
- Compute-draw separation: update computation first, then redraw uniformly
- Local clear instead of full-screen wipe: sparse particles only clear their surrounding area
- Dual-layer Canvas separation: one layer draws static background (once), one layer draws dynamic particles (clear and redraw each frame)
- ImageData pixel-level rendering: when particles are single pixels, use ImageData to write pixels directly, reaching extremely large scale
- OffscreenCanvas + Web Worker: move entire simulation+rendering off main thread, keeping main thread responsive
Particle animations are commonly used for: flow field/wind field visualization, network/relationship force-directed graphs, heat and density maps, background ambient effects, large-scale point clouds.
Canvas is suitable for scenarios with large numbers of elements where individual interaction with each element isn’t needed (complementary to SVG’s DOM bottleneck).
New Trends: Houdini, WAAPI, Variable Fonts
Houdini is an umbrella of APIs that let developers intervene in the browser rendering engine:
@property: next-generation CSS variables, now fully supported by all modern browsers, can declare types and initial values for custom properties, unlocking stronger animation and computation capabilities- Animation Worklet: Houdini’s most powerful API, allows running animation logic in compositor thread, not blocked by main thread; but lowest browser support, currently only Chrome fully supports
Web Animations API (WAAPI) unifies CSS and SVG animation capabilities, allowing hardware-accelerated DOM element animation via JavaScript (like Element.animate(keyframes, options)). It combines CSS animation’s declarative power with JS’s imperative control, the modernization direction for SMIL/CSS animation.
| |
Variable fonts compress multiple axes of font weight (weight, width, slant, etc.) into a single font file, and font-variation-settings is an animatable CSS property, opening typography effects impossible with static fonts. Browser support: Chrome 66+, Firefox 62+, Safari 11+, Edge 17+, global coverage over 97% in 2024.
Animation Design Principles
Animation isn’t the goal, it’s the means.
- Perceived performance: use transitions to mask loading and computation delays, making users “feel faster”
prefers-reduced-motion: respect user accessibility preferences, degrade or disable animations- Meaningful motion: animation should convey state changes, data mapping, or causal relationships, not decoration
- Performance priority: prioritize compositor-friendly properties (transform, opacity), avoid triggering layout/repaint; prioritize Canvas/WebGL for large data
Technology Selection Decision Tree
flowchart TD
A[Animation needs] --> B[CSS Animation<br/>95% blog needs]
A --> C[Lottie<br/>Designer effects]
A --> D[GSAP<br/>Multi-element timing]
A --> E[D3.js<br/>Data-driven transitions]
A --> F[Three.js<br/>3D massive data]
style A fill:#FF9800,color:#fff
style B fill:#4CAF50,color:#fff
style C fill:#9C27B0,color:#fff
style D fill:#2196F3,color:#fff
style E fill:#FF9800,color:#fff
style F fill:#f44336,color:#fffSimple state toggle → CSS Animation. 95% of blog animation needs are here.
Designer-provided interactive animations → Lottie. Design-development decoupling, cross-platform consistency.
Multi-element choreography → GSAP. Timeline abstraction, scroll-driven, SVG morphing.
Data-driven visualization → D3.js + SVG/Canvas. D3 handles data mapping, SVG/Canvas handles rendering.
3D space or massive data → Three.js/deck.gl. GPU acceleration, million-level point clouds.
Particle effects → Canvas. Object pooling, dual-layer Canvas, OffscreenCanvas + Web Worker.
Conclusion
The animation technology stack looks complex, but the core is understanding the boundaries of each path. If CSS can solve it, never introduce GSAP. If designer provides it, use Lottie. If data-driven, use D3/GSAP/Canvas. If 3D, use Three.js.
In blog scenarios, the vast majority of animation needs stay at the CSS level. If unsure, start with CSS, then look up when it doesn’t work.
After all, the best technology decision is knowing when to stop.