CSS vs JavaScript vs SMIL for SVG Animation
Compare CSS, JavaScript, and SMIL for SVG animation. See code examples for each, learn browser support, and find the right technique for your project.
Vector Wizard Team
April 26, 2026 · Updated May 10, 2026 · 7 min read
CSS vs JavaScript vs SMIL for SVG Animation
Choosing the right animation technique for your SVG can save hours of debugging and deliver smoother results. This guide compares CSS, JavaScript, and SMIL across real code examples, browser support, performance, and practical use cases.
Quick comparison
| Feature | CSS | JavaScript | SMIL | |---|---|---|---| | Syntax complexity | Low | Medium | Low | | Browser support | Excellent | Excellent | Good (deprecated in some contexts) | | Performance | GPU-accelerated | CPU-bound (unless using WAAPI) | GPU-accelerated | | Interactivity | Limited (hover, focus) | Full control | None | | Path morphing | No | Yes | Yes | | Sequence control | Difficult | Easy (timelines) | Medium | | Bundle size | 0 KB | 0–50 KB (library) | 0 KB | | Learning curve | Low | Medium | Low |
CSS Animation for SVG
CSS is the most common choice for SVG animation. If you know how to animate HTML elements, you already know how to animate SVGs.
Example: Pulsing Dot
<svg viewBox="0 0 100 100">
<circle class="pulse" cx="50" cy="50" r="20" fill="#9333ea"/>
</svg>
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.5); opacity: 0.7; }
}
.pulse {
animation: pulse 2s ease-in-out infinite;
transform-origin: center;
}
Example: Draw-On Effect (Stroke Animation)
@keyframes draw {
from { stroke-dashoffset: 1000; }
to { stroke-dashoffset: 0; }
}
.path-draw {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: draw 3s ease-out forwards;
}
What CSS Can Animate on SVG
transform(translate, rotate, scale, skew)opacityfillandstrokecolorsstroke-dasharrayandstroke-dashoffsetfilter(blur, drop-shadow)
What CSS Cannot Do
- Animate path data (morph one shape into another)
- Animate the
dattribute of a<path> - Complex choreographed sequences with callbacks
- Dynamic values based on user input or data
For 80% of web animations, CSS is sufficient. Start here and only upgrade to JavaScript when you hit a limitation.
JavaScript Animation for SVG
JavaScript unlocks full programmatic control. You can animate any attribute, respond to events, and build complex timelines.
Web Animations API (WAAPI)
The modern, browser-native approach:
const circle = document.querySelector('circle');
const animation = circle.animate([
{ r: 20, fill: '#9333ea' },
{ r: 30, fill: '#ec4899' },
{ r: 20, fill: '#9333ea' }
], {
duration: 2000,
iterations: Infinity,
easing: 'ease-in-out'
});
// Pause on hover
circle.addEventListener('mouseenter', () => animation.pause());
circle.addEventListener('mouseleave', () => animation.play());
GSAP (GreenSock Animation Platform)
The industry standard for complex animation:
gsap.to('.circle', {
r: 30,
fill: '#ec4899',
duration: 1,
yoyo: true,
repeat: -1,
ease: 'power2.inOut'
});
// Timeline for sequenced animations
const tl = gsap.timeline();
tl.to('.logo', { opacity: 1, duration: 0.5 })
.to('.tagline', { y: 0, opacity: 1, duration: 0.5 }, '-=0.3')
.to('.cta', { scale: 1, duration: 0.4 }, '-=0.2');
When to Use JavaScript
- Path morphing (animating the
dattribute) - Physics-based or spring animations
- Scroll-triggered animations
- Animations driven by real-time data
- Complex timelines with multiple elements
- Games and interactive experiences
GSAP is powerful but adds approximately 25 KB (gzipped) to your bundle. For simple animations, WAAPI or CSS is sufficient and keeps your bundle lean.
SMIL Animation for SVG
SMIL (Synchronized Multimedia Integration Language) is SVG's native animation syntax. It is declarative, meaning you describe what should happen and the browser handles the rest.
Example: Basic Animation
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="20" fill="#9333ea">
<animate
attributeName="r"
values="20;30;20"
dur="2s"
repeatCount="indefinite"
/>
</circle>
</svg>
Example: Motion Along a Path
<svg viewBox="0 0 200 200">
<path id="motionPath" d="M10,100 Q100,10 190,100" fill="none" stroke="#ddd"/>
<circle r="8" fill="#9333ea">
<animateMotion dur="3s" repeatCount="indefinite">
<mpath href="#motionPath"/>
</animateMotion>
</circle>
</svg>
Example: Path Morphing
<svg viewBox="0 0 100 100">
<path fill="#9333ea">
<animate
attributeName="d"
values="M50,10 L90,90 L10,90 Z;
M50,10 C70,10 90,30 90,50 C90,70 70,90 50,90 C30,90 10,70 10,50 C10,30 30,10 50,10 Z;
M50,10 L90,90 L10,90 Z"
dur="3s"
repeatCount="indefinite"
/>
</path>
</svg>
SMIL Browser Support Reality
SMIL works in all modern browsers but has a complicated history:
- Chrome deprecated SMIL for CSS animations in 2015, then un-deprecated it after developer backlash
- SMIL for attribute animation (like
r,cx,fill) still works everywhere - SMIL is not deprecated for SVG-native attribute animation
- CSS animations cannot replace SMIL for path morphing or motion along paths
Despite rumors of deprecation, SMIL remains the only declarative way to animate path data and motion along paths in SVG. For these specific use cases, it is still the best choice.
Decision framework
Use this flowchart to choose your approach:
Does your animation need path morphing?
├── YES → Can users interact with it?
│ ├── YES → JavaScript (GSAP/WAAPI)
│ └── NO → SMIL
└── NO → Does it need complex sequencing?
├── YES → JavaScript (GSAP timeline)
└── NO → Is it triggered by hover/scroll?
├── YES → CSS
└── NO → Simple loop?
├── YES → CSS or SMIL
└── NO → JavaScript (WAAPI)
Performance deep dive
CSS Animation Performance
CSS animations of transform and opacity are composited on the GPU. This means they run at 60fps without blocking the main thread. However, animating width, height, top, left, or margin forces the browser to recalculate layout every frame, causing jank.
Fast properties: transform, opacity, filter
Slow properties: width, height, top, left, margin, padding
JavaScript Animation Performance
WAAPI animations run on the browser's animation thread, just like CSS. Traditional JavaScript animations using setInterval or requestAnimationFrame with DOM manipulation run on the main thread and can cause jank if the frame budget is exceeded.
GSAP is highly optimized and uses requestAnimationFrame efficiently. It also batches DOM reads and writes to avoid layout thrashing.
SMIL Performance
SMIL animations are handled by the browser's SVG renderer, which is GPU-accelerated for transforms and opacity. SMIL has zero JavaScript overhead, making it efficient for simple looping animations.
Code example: same animation, three ways
Here is a circle that grows and changes color, implemented in all three techniques:
CSS Version
@keyframes grow {
0%, 100% { transform: scale(1); fill: #9333ea; }
50% { transform: scale(1.5); fill: #ec4899; }
}
.circle-css {
animation: grow 2s ease-in-out infinite;
transform-origin: center;
}
JavaScript (WAAPI) Version
circle.animate([
{ transform: 'scale(1)', fill: '#9333ea' },
{ transform: 'scale(1.5)', fill: '#ec4899' },
{ transform: 'scale(1)', fill: '#9333ea' }
], { duration: 2000, iterations: Infinity });
SMIL Version
<circle cx="50" cy="50" r="20" fill="#9333ea">
<animateTransform
attributeName="transform"
type="scale"
values="1;1.5;1"
dur="2s"
repeatCount="indefinite"
additive="sum"
/>
<animate
attributeName="fill"
values="#9333ea;#ec4899;#9333ea"
dur="2s"
repeatCount="indefinite"
/>
</circle>
Accessibility considerations
All three approaches should respect prefers-reduced-motion:
@media (prefers-reduced-motion: reduce) {
.animated-element {
animation: none !important;
transition: none !important;
}
}
For JavaScript animations:
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!prefersReduced) {
// Start animation
}
Bottom line
- Use CSS for 80% of animations. It is fast, simple, and hardware-accelerated.
- Use JavaScript when you need path morphing, complex timelines, or interactivity.
- Use SMIL for declarative path morphing and motion along paths without JavaScript.
Most professional projects use a combination: CSS for UI states, JavaScript for complex sequences, and SMIL for specific SVG-native effects.
Ready to animate without writing all this code? Try Vector Wizard's SVG Animator and generate CSS, JavaScript, or SMIL animations from a simple description.