SVG Animation — SMIL, CSS & JavaScript
In this tutorial, you'll learn about SVG Animation. We cover key concepts, practical examples, and best practices.
SVG animation brings vector graphics to life using three approaches — declarative SMIL animations, CSS transitions and keyframes, and JavaScript libraries for complex motion sequences.
In this tutorial, you'll learn SVG animation — how to animate vector graphics using SMIL (declarative SVG animations), CSS transitions and keyframes on SVG elements, and JavaScript-driven motion with the Web Animations API and GSAP. SVG animation is resolution-independent, lightweight, and essential for icons, data visualizations, logos, and interactive illustrations. By the end, you'll build an animated threat-detection dashboard icon.
Real-world use: Durga Antivirus Pro uses animated SVG icons for real-time threat indicators — pulsing shields, rotating scan radars, and animated progress rings. DodaZIP uses SVG loading spinners and animated folder icons.
flowchart TD A[SVG Animation] --> B[SMIL] A --> C[CSS] A --> D[JavaScript] B --> E[] B --> F[ ] B --> G[ ] C --> H[transition / animation] C --> I[CSS properties] D --> J[Web Animations API] D --> K[GSAP / anime.js] E & F & G & H & I & J & K --> L[Animated SVG Output]
SVG Structure Recap
Before animating, understand the SVG coordinate system.
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="#6366f1" id="myCircle"/>
</svg>
Animations target SVG elements by ID or class, transforming their visual properties over time.
SMIL Animations
SMIL (Synchronized Multimedia Integration Language) is SVG's native animation system with <animate>, <animateTransform>, and <animateMotion> elements.
<svg viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">
<!-- Pulsing circle -->
<circle cx="100" cy="100" r="40" fill="#6366f1">
<animate
attributeName="r"
values="40; 50; 40"
dur="2s"
repeatCount="indefinite"
calcMode="spline"
keySplines="0.42 0 0.58 1; 0.42 0 0.58 1"
/>
<animate
attributeName="opacity"
values="1; 0.6; 1"
dur="2s"
repeatCount="indefinite"
/>
</circle>
<!-- Moving rectangle along a path -->
<rect x="0" y="80" width="20" height="20" fill="#f59e0b">
<animateMotion
dur="3s"
repeatCount="indefinite"
path="M50,90 C100,30 200,150 250,90"
/>
</rect>
<!-- Color cycling -->
<rect x="180" y="50" width="60" height="60" rx="8">
<animate
attributeName="fill"
values="#6366f1; #ef4444; #10b981; #6366f1"
dur="4s"
repeatCount="indefinite"
/>
</rect>
</svg>
Expected behavior: A pulsing blue circle, a yellow rectangle tracing a bezier path, and a box cycling through three colors — all animating declaratively without JavaScript.
Animating SVG with CSS
CSS animations and transitions work on SVG elements, though not all CSS properties apply.
/* SVG element styling */
svg .shield-icon {
transition: transform 0.3s ease, fill 0.3s ease;
}
svg .shield-icon:hover {
transform: scale(1.2);
fill: #ef4444;
}
/* Keyframe animation on SVG */
@keyframes rotate-radar {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
svg .radar-line {
transform-origin: 100px 100px;
animation: rotate-radar 3s linear infinite;
}
@keyframes pulse-threat {
0% { r: 5; opacity: 1; }
50% { r: 15; opacity: 0.3; }
100% { r: 5; opacity: 1; }
}
svg .threat-dot {
animation: pulse-threat 1.5s ease-in-out infinite;
animation-delay: calc(var(--index) * 0.2s);
}
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<style>
.threat-dot:nth-child(1) { --index: 0; }
.threat-dot:nth-child(2) { --index: 1; }
.threat-dot:nth-child(3) { --index: 2; }
</style>
<circle class="threat-dot" cx="60" cy="80" r="5" fill="#ef4444"/>
<circle class="threat-dot" cx="140" cy="80" r="5" fill="#ef4444"/>
<circle class="threat-dot" cx="100" cy="140" r="5" fill="#ef4444"/>
</svg>
Expected output: Three red dots pulsing at staggered intervals, simulating threat indicators on a security dashboard.
JavaScript-Driven SVG Animation
For complex sequencing and interactivity, use JavaScript with the Web Animations API.
// Animate SVG elements with Web Animations API
const shield = document.getElementById('shield-path');
const scanCircle = document.getElementById('scan-ring');
// Chain SVG-specific animations
async function runScanSequence() {
// Shield glow
await shield.animate(
[
{ fill: '#6366f1', filter: 'drop-shadow(0 0 0 rgba(99,102,241,0))' },
{ fill: '#4f46e5', filter: 'drop-shadow(0 0 10px rgba(99,102,241,0.8))' },
{ fill: '#6366f1', filter: 'drop-shadow(0 0 0 rgba(99,102,241,0))' }
],
{ duration: 800, easing: 'ease-in-out' }
).finished;
// Scan ring expansion
await scanCircle.animate(
[
{ r: 20, opacity: 1 },
{ r: 60, opacity: 0 }
],
{ duration: 1000, easing: 'ease-out' }
).finished;
// Repeat scan
runScanSequence();
}
runScanSequence();
GSAP with SVG
GSAP provides advanced SVG animation features like morphing and timeline sequencing.
// Include GSAP: npm install gsap
import { gsap } from 'gsap';
import { MorphSVGPlugin } from 'gsap/MorphSVGPlugin';
gsap.registerPlugin(MorphSVGPlugin);
// Morphing between shapes
gsap.to('#morph-target', {
duration: 1.5,
morphSVG: '#shield-shape',
ease: 'power2.inOut'
});
// Timeline sequence for complex SVG animations
const tl = gsap.timeline({ repeat: -1, yoyo: true });
tl.to('.scan-ring', { duration: 1, scale: 1.5, opacity: 0, ease: 'power2.out' })
.to('.scan-ring', { duration: 0, scale: 1, opacity: 1 })
.to('.threat-pulse', { duration: 0.4, scale: 1.3, ease: 'power1.out' })
.to('.threat-pulse', { duration: 0.4, scale: 1, ease: 'bounce.out' })
.to('.status-bar', { duration: 0.5, attr: { width: 180 }, ease: 'power2.inOut' })
.to('.status-text', { duration: 0.3, text: 'Scan Complete', ease: 'none' });
Stroke Animations
Animate SVG strokes to create drawing effects for icons and logos.
@keyframes draw-line {
from { stroke-dashoffset: 1000; }
to { stroke-dashoffset: 0; }
}
.draw-path {
stroke-dasharray: 1000;
animation: draw-line 3s ease-in-out forwards;
}
// Programmatic stroke animation
const path = document.getElementById('icon-path');
const length = path.getTotalLength();
path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;
path.animate(
[
{ strokeDashoffset: length },
{ strokeDashoffset: 0 }
],
{ duration: 2000, easing: 'ease-in-out', fill: 'forwards' }
);
Expected output: An SVG icon where the outline draws itself progressively, like a digital sketch.
Interactive SVG Dashboard
Combine techniques for a security dashboard widget.
<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="scanGrad">
<stop offset="0%" stop-color="rgba(99,102,241,0.3)"/>
<stop offset="100%" stop-color="rgba(99,102,241,0)"/>
</radialGradient>
</defs>
<!-- Scan radar background -->
<circle cx="150" cy="150" r="100" fill="url(#scanGrad)"/>
<!-- Animated scan line -->
<line x1="150" y1="150" x2="250" y2="150"
stroke="#6366f1" stroke-width="2" class="scan-line"/>
<!-- Threat dots with staggered animation -->
<circle cx="120" cy="100" r="4" fill="#ef4444" class="threat">
<animate attributeName="r" values="4; 8; 4" dur="1.5s" begin="0s" repeatCount="indefinite"/>
</circle>
<circle cx="180" cy="130" r="4" fill="#f59e0b" class="threat">
<animate attributeName="r" values="4; 8; 4" dur="1.5s" begin="0.3s" repeatCount="indefinite"/>
</circle>
<circle cx="90" cy="160" r="4" fill="#10b981" class="threat safe">
<animate attributeName="r" values="4; 8; 4" dur="1.5s" begin="0.6s" repeatCount="indefinite"/>
</circle>
</svg>
.scan-line {
transform-origin: 150px 150px;
animation: rotate 3s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.threat:hover {
filter: drop-shadow(0 0 6px currentColor);
cursor: pointer;
}
Performance Considerations
SVG animation performance depends on what properties you animate and how complex the shapes are.
/* Optimal: composited properties */
transform: translateX(100px);
transform: rotate(45deg);
opacity: 0.5;
/* Acceptable but repaints */
fill: #ef4444;
stroke: #6366f1;
stroke-dashoffset: 100;
/* Performance tip: contain complex SVGs */
svg {
contain: layout style paint;
}
/* Use will-change sparingly */
svg .active {
will-change: transform;
}
Common Errors
- CSS animations not working on SVG — Not all CSS properties apply to SVG.
transform-origindefaults to(0,0)in SVG, not the element center. Set it explicitly withtransform-origin: centeror pixel coordinates. - SMIL animations conflicting with CSS — If both SMIL and CSS animate the same attribute, one overrides the other inconsistently. Use one approach per attribute.
stroke-dasharraynot matching path length — For drawing effects,stroke-dasharrayandstroke-dashoffsetmust equalpath.getTotalLength(). Use JavaScript to get the exact length.- SVG element not reacting to hover — If the SVG shape is inside a
<g>with no fill, hover only triggers on the visible stroke. Addpointer-events: allor set a transparent fill. - Animation jank on complex SVGs — SVGs with hundreds of nodes animate poorly. Simplify paths with SVG optimization tools, use
contain: layout style paint, and prefertransformover attribute animation.
Practice Questions
Challenge
Build an animated SVG threat detection dashboard that includes: a rotating scan radar with pulsating threat dots, an animated shield icon that glows when threats are detected, stroke-animated progress rings showing scan percentage, color-coded threat indicators (green = safe, yellow = suspicious, red = critical), and hover interaction that displays threat details.
Real-World Task
Create the animated threat indicator icon set for Durga Antivirus Pro. Using SVG, design: a shield icon with a stroke-draw entrance animation, a scan radar with a rotating line and pulse ring, threat-level icons (safe, warning, critical) with appropriate color animations, a progress ring that animates from 0 to 100% during scanning. All animations must respect prefers-reduced-motion and work in browsers as old as 2 versions back.
Related: Web Animations Guide | Previous: CSS Fundamentals | Related: HTML5 Canvas
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro