Back to BlogTechnical Guides

SVG Animations: The Complete Guide to Animating Vector Graphics in 2025

SVG Genie Team14 min read

Static SVGs are powerful. Animated SVGs are unforgettable.

The same vector graphic that works well as a static image becomes exponentially more engaging when it moves, morphs, or responds to user interaction. And the best part? SVG animations are lighter than video, sharper than GIFs, and infinitely more controllable than either.

In this guide, we'll cover everything you need to know about animating SVGs in 2025.

Why Animate SVGs?

Before diving into how, let's address why:

Performance Benefits

  • SVG animations are GPU-accelerated when done right
  • File sizes stay tiny compared to video or animated GIFs
  • No quality loss at any screen resolution

User Experience Benefits

  • Draws attention to key elements
  • Provides visual feedback on interactions
  • Creates memorable, delightful moments
  • Guides users through interfaces

Technical Benefits

  • Full control via CSS and JavaScript
  • Easy to make responsive
  • Accessible with proper implementation
  • Works in all modern browsers

Three Ways to Animate SVGs

There are three main approaches to SVG animation, each with distinct strengths:

1. CSS Animations

The most common approach. Use standard CSS transitions and keyframes on SVG elements.

/* Simple hover transition */
.icon-path {
  fill: #6366f1;
  transition: fill 0.3s ease, transform 0.3s ease;
}

.icon-path:hover {
  fill: #f97316;
  transform: scale(1.1);
}

Best for: Hover effects, simple transitions, loading states

2. JavaScript Animations

Maximum control with libraries like GSAP, Anime.js, or vanilla JS.

// Using GSAP
gsap.to(".svg-element", {
  rotation: 360,
  duration: 2,
  ease: "power2.inOut",
  repeat: -1
});

Best for: Complex sequences, scroll-triggered animations, interactive graphics

3. SMIL (SVG Animation)

Native SVG animation syntax embedded in the SVG itself.

<circle cx="50" cy="50" r="20" fill="#6366f1">
  <animate
    attributeName="r"
    values="20;30;20"
    dur="1s"
    repeatCount="indefinite"
  />
</circle>

Best for: Self-contained animated icons, simple looping animations

Note: SMIL has limited browser support (no IE, limited Edge). For production, CSS or JS is usually safer.

CSS Animation Fundamentals

Let's start with what most developers will use: CSS.

Transforms

The transform property is your workhorse. Apply it to SVG elements just like HTML:

.svg-element {
  transform-origin: center center;
  transition: transform 0.3s ease;
}

.svg-element:hover {
  transform: rotate(15deg) scale(1.1);
}

Important: Set transform-origin explicitly. SVG elements default to the top-left corner of the SVG canvas, not the element itself.

Animatable Properties

These SVG-specific properties can be animated:

| Property | What It Does | Example Use | |----------|--------------|-------------| | fill | Shape fill color | Color transitions on hover | | stroke | Outline color | Focus indicators | | stroke-width | Outline thickness | Emphasis effects | | stroke-dashoffset | Dash position | Drawing animations | | opacity | Transparency | Fade in/out | | r (circles) | Radius | Pulsing effects | | cx, cy | Center position | Movement |

Keyframe Animations

For more complex sequences, use @keyframes:

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.1);
    opacity: 0.8;
  }
}

.pulse-icon {
  animation: pulse 2s ease-in-out infinite;
}

The Famous Line Drawing Effect

One of the most popular SVG animations is the "self-drawing" effect. Here's how it works:

Step 1: Understand stroke-dasharray

This property creates dashed lines:

path {
  stroke-dasharray: 10 5; /* 10px dash, 5px gap */
}

Step 2: Make One Big Dash

Set the dash length equal to the total path length:

path {
  stroke-dasharray: 500; /* Length of entire path */
  stroke-dashoffset: 500; /* Hide it completely */
}

Step 3: Animate the Offset

path {
  stroke-dasharray: 500;
  stroke-dashoffset: 500;
  animation: draw 2s ease forwards;
}

@keyframes draw {
  to {
    stroke-dashoffset: 0;
  }
}

Getting Path Length

How do you know the path length? Two options:

JavaScript:

const path = document.querySelector('path');
const length = path.getTotalLength();
console.log(length); // Use this value

pathLength attribute:

<path d="..." pathLength="100" />

Now you can use stroke-dasharray: 100 regardless of actual length.

Complete Example

<svg viewBox="0 0 100 100" class="draw-svg">
  <path
    d="M10,50 Q50,10 90,50 Q50,90 10,50"
    pathLength="100"
    fill="none"
    stroke="#6366f1"
    stroke-width="2"
  />
</svg>

<style>
.draw-svg path {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: draw 2s ease forwards;
}

@keyframes draw {
  to { stroke-dashoffset: 0; }
}
</style>

This creates an elegant infinity symbol that draws itself on page load.

Interactive Animations

SVGs can respond to user interaction in ways other formats can't.

Hover States

<svg class="interactive-icon" viewBox="0 0 24 24">
  <circle class="bg" cx="12" cy="12" r="10" />
  <path class="icon" d="M12,6 L12,18 M6,12 L18,12" />
</svg>

<style>
.interactive-icon .bg {
  fill: #18181b;
  transition: fill 0.3s ease;
}

.interactive-icon .icon {
  stroke: #6366f1;
  stroke-width: 2;
  transition: stroke 0.3s ease, transform 0.3s ease;
  transform-origin: center;
}

.interactive-icon:hover .bg {
  fill: #6366f1;
}

.interactive-icon:hover .icon {
  stroke: white;
  transform: rotate(90deg);
}
</style>

This creates a plus icon that rotates and inverts colors on hover.

Click Animations

const button = document.querySelector('.svg-button');
const checkmark = button.querySelector('.checkmark');

button.addEventListener('click', () => {
  checkmark.style.strokeDashoffset = '0';
  button.classList.add('clicked');
});

Loading Animations

SVG loaders are smooth, lightweight, and infinitely customizable.

Simple Spinner

<svg class="spinner" viewBox="0 0 50 50">
  <circle
    cx="25" cy="25" r="20"
    fill="none"
    stroke="#6366f1"
    stroke-width="4"
    stroke-linecap="round"
    stroke-dasharray="80 200"
  />
</svg>

<style>
.spinner {
  animation: rotate 1s linear infinite;
}

.spinner circle {
  animation: dash 1.5s ease-in-out infinite;
}

@keyframes rotate {
  to { transform: rotate(360deg); }
}

@keyframes dash {
  0% {
    stroke-dasharray: 1 200;
    stroke-dashoffset: 0;
  }
  50% {
    stroke-dasharray: 100 200;
    stroke-dashoffset: -35;
  }
  100% {
    stroke-dasharray: 100 200;
    stroke-dashoffset: -125;
  }
}
</style>

This creates the classic Material Design spinner effect.

Pulsing Dots

<svg class="dots" viewBox="0 0 60 20">
  <circle class="dot" cx="10" cy="10" r="5" />
  <circle class="dot" cx="30" cy="10" r="5" />
  <circle class="dot" cx="50" cy="10" r="5" />
</svg>

<style>
.dot {
  fill: #6366f1;
  animation: bounce 1.4s ease-in-out infinite;
}

.dot:nth-child(1) { animation-delay: 0s; }
.dot:nth-child(2) { animation-delay: 0.2s; }
.dot:nth-child(3) { animation-delay: 0.4s; }

@keyframes bounce {
  0%, 80%, 100% {
    transform: translateY(0);
    opacity: 1;
  }
  40% {
    transform: translateY(-10px);
    opacity: 0.5;
  }
}
</style>

Morphing Animations

SVG paths can morph between shapes if they have the same number of points.

Simple Morph with CSS

<svg viewBox="0 0 100 100">
  <path class="morph" d="M50,10 L90,90 L10,90 Z" />
</svg>

<style>
.morph {
  fill: #6366f1;
  transition: d 0.5s ease;
}

.morph:hover {
  d: path("M10,10 L90,10 L90,90 L10,90 Z");
}
</style>

Triangle morphs to square on hover.

Note: CSS d property animation has limited browser support. For production, use a library like GSAP MorphSVG.

JavaScript Morphing with Flubber

For complex morphs between different shapes:

import { interpolate } from 'flubber';

const triangle = "M50,10 L90,90 L10,90 Z";
const circle = "M50,10 A40,40 0 1,1 50,90 A40,40 0 1,1 50,10";

const interpolator = interpolate(triangle, circle);

function animate(progress) {
  path.setAttribute('d', interpolator(progress));
}

Performance Optimization

Smooth animations require attention to performance.

Use transform and opacity

These properties are GPU-accelerated:

/* Good - GPU accelerated */
.element {
  transform: translateX(100px);
  opacity: 0.5;
}

/* Avoid - causes repaints */
.element {
  left: 100px;
  fill: rgba(0,0,0,0.5);
}

will-change Hint

Tell the browser to optimize:

.animated-element {
  will-change: transform, opacity;
}

Caution: Don't overuse. Only apply to elements that will actually animate.

Reduce Complexity

  • Simplify paths (fewer nodes = faster rendering)
  • Use SVG Minify to optimize file size
  • Avoid animating too many elements simultaneously
  • Use requestAnimationFrame for JavaScript animations

Test on Real Devices

Animations that run smooth on your M2 MacBook might stutter on a mid-range Android phone. Always test on target devices.

Scroll-Triggered Animations

Modern websites often animate SVGs as users scroll.

Intersection Observer

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('animate');
    }
  });
}, { threshold: 0.5 });

document.querySelectorAll('.scroll-svg').forEach(svg => {
  observer.observe(svg);
});

With Framer Motion (React)

import { motion, useInView } from 'framer-motion';

function AnimatedIcon() {
  const ref = useRef(null);
  const isInView = useInView(ref, { once: true });

  return (
    <motion.svg
      ref={ref}
      initial={{ pathLength: 0 }}
      animate={isInView ? { pathLength: 1 } : { pathLength: 0 }}
      transition={{ duration: 2, ease: "easeInOut" }}
    >
      <motion.path d="..." />
    </motion.svg>
  );
}

Accessibility Considerations

Animated SVGs need extra attention for accessibility.

Respect Motion Preferences

@media (prefers-reduced-motion: reduce) {
  .animated-svg,
  .animated-svg * {
    animation: none !important;
    transition: none !important;
  }
}

This disables animations for users who've indicated they prefer reduced motion.

Provide Pause Controls

For continuously animated SVGs:

const svg = document.querySelector('.looping-animation');
const pauseBtn = document.querySelector('.pause-btn');

pauseBtn.addEventListener('click', () => {
  svg.style.animationPlayState =
    svg.style.animationPlayState === 'paused' ? 'running' : 'paused';
});

Don't Rely on Animation Alone

Never convey critical information only through animation. Always provide static alternatives or text descriptions.

Real-World Examples

Animated Logo

<svg class="logo" viewBox="0 0 100 100">
  <circle class="logo-bg" cx="50" cy="50" r="45" />
  <path class="logo-mark" d="M30,50 L45,65 L70,35" pathLength="100" />
</svg>

<style>
.logo-bg {
  fill: #6366f1;
  transform-origin: center;
  animation: pulse 3s ease-in-out infinite;
}

.logo-mark {
  fill: none;
  stroke: white;
  stroke-width: 6;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: draw 1s ease forwards 0.5s;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

@keyframes draw {
  to { stroke-dashoffset: 0; }
}
</style>

Success Checkmark

<svg class="success-check" viewBox="0 0 52 52">
  <circle class="check-circle" cx="26" cy="26" r="25" />
  <path class="check-mark" d="M14,27 L22,35 L38,16" pathLength="100" />
</svg>

<style>
.check-circle {
  fill: none;
  stroke: #10b981;
  stroke-width: 2;
  stroke-dasharray: 166;
  stroke-dashoffset: 166;
  animation: circle-draw 0.6s ease forwards;
}

.check-mark {
  fill: none;
  stroke: #10b981;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: check-draw 0.3s ease forwards 0.6s;
}

@keyframes circle-draw {
  to { stroke-dashoffset: 0; }
}

@keyframes check-draw {
  to { stroke-dashoffset: 0; }
}
</style>

Tools for SVG Animation

Design Tools

Libraries

  • GSAP - Industry standard for complex animations
  • Anime.js - Lightweight and powerful
  • Framer Motion - Best for React projects
  • Lottie - For After Effects animations

Optimization

  • SVG Minify - Reduce file size before animating
  • SVGOMG - Advanced optimization options

Key Takeaways

  1. CSS is usually enough - Start simple before reaching for JavaScript
  2. stroke-dashoffset is your friend - Powers most drawing animations
  3. Transform and opacity are fast - Stick to GPU-accelerated properties
  4. Respect user preferences - Always support prefers-reduced-motion
  5. Test performance - Smooth on desktop doesn't mean smooth everywhere
  6. Keep it purposeful - Animate to enhance, not distract

Start Animating

Ready to bring your vectors to life?

  1. Create an SVG - Generate a base graphic with AI
  2. Edit in SVG Editor - Prepare structure for animation
  3. Test in Playground - Experiment with animation code
  4. Optimize with Minify - Reduce final file size

The best SVG animations are subtle, purposeful, and delightful. Start with simple hover effects and work your way up to complex sequences as you build confidence.


Related Articles:

Ready to create your own vectors?

Start designing with AI-powered precision today.

Get Started Free