Skip to content

SVG Animation — SMIL, CSS & JavaScript

DodaTech Updated 2026-06-24 8 min read

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

  1. CSS animations not working on SVG — Not all CSS properties apply to SVG. transform-origin defaults to (0,0) in SVG, not the element center. Set it explicitly with transform-origin: center or pixel coordinates.
  2. SMIL animations conflicting with CSS — If both SMIL and CSS animate the same attribute, one overrides the other inconsistently. Use one approach per attribute.
  3. stroke-dasharray not matching path length — For drawing effects, stroke-dasharray and stroke-dashoffset must equal path.getTotalLength(). Use JavaScript to get the exact length.
  4. SVG element not reacting to hover — If the SVG shape is inside a <g> with no fill, hover only triggers on the visible stroke. Add pointer-events: all or set a transparent fill.
  5. Animation jank on complex SVGs — SVGs with hundreds of nodes animate poorly. Simplify paths with SVG optimization tools, use contain: layout style paint, and prefer transform over attribute animation.

Practice Questions

What is SMIL in SVG?

SMIL (Synchronized Multimedia Integration Language) is SVG's built-in XML-based animation system. It uses elements like <animate>, <animateTransform>, and <animateMotion> to animate SVG attributes declaratively without CSS or JavaScript.

How do CSS animations on SVGs differ from HTML CSS animations?

SVG CSS animations use a different transform-origin default (0,0 instead of element center). Some CSS properties (like filter) have different support levels on SVG vs HTML. SVG geometric properties (cx, r, d) cannot be animated with CSS — use SMIL or JavaScript for those.

When should I use JavaScript vs SMIL for SVG animations?

Use SMIL for simple, declarative loops (pulsing, rotating) that run independently. Use JavaScript for interactive animations (click-triggered, chained sequences), dynamic property calculation, and integration with application state.

What is a stroke-dasharray drawing animation?

It animates stroke-dashoffset from the path length to 0, creating the illusion of the path being drawn. Set stroke-dasharray equal to the path length, then animate stroke-dashoffset from that length to 0.

Can SVG animations use GPU acceleration?

Yes, but only for transform and opacity on SVG elements. Animate transform (translate, rotate, scale) and opacity for GPU-accelerated, jank-free SVG animations. Attribute animations (cx, r, fill) trigger repaints

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