TutorialMay 2026·11 min read

How to Animate SVG Icons Step by Step

SVG icons are the perfect candidate for CSS animation — they are resolution-independent, tiny in file size, and every shape inside them is individually targetable with CSS selectors. This guide walks through the four most useful icon animation patterns, with copy-paste code for each.

Why Animate SVG Icons Specifically?

Unlike raster icons (PNG, WebP), SVG icons expose their internal structure to CSS and JavaScript. A three-bar hamburger menu, for example, is just three <line> or <rect> elements — each of which you can rotate, translate, or fade independently.

This makes it trivial to animate common UI state transitions — hamburger to X, plus to minus, play to pause, loading spinner — entirely in CSS with no JavaScript and no external library.

Pattern 1: Rotating Spinner

The simplest animated SVG icon is a loading spinner. A circle with a partial stroke gap rotated continuously creates the classic indeterminate spinner used across every design system.

<!-- SVG markup -->
<svg viewBox="0 0 24 24" width="40" height="40">
  <circle
    class="spinner-track"
    cx="12" cy="12" r="10"
    fill="none"
    stroke="#2A2A2A"
    stroke-width="2"
  />
  <circle
    class="spinner-head"
    cx="12" cy="12" r="10"
    fill="none"
    stroke="#6366f1"
    stroke-width="2"
    stroke-linecap="round"
    stroke-dasharray="16 47"
  />
</svg>
/* CSS */
.spinner-head {
  transform-origin: 50% 50%;
  animation: spin 900ms linear infinite;
}

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

The stroke-dasharray creates the gap — 16px of visible stroke, 47px gap (roughly the remaining circumference of a circle with r=10).

Pattern 2: Draw-On Stroke Effect

The draw-on effect makes an SVG path appear to be drawn in real time. It works by setting stroke-dasharray to the total path length and animating stroke-dashoffset from that value down to zero.

How to get path length

In DevTools: document.querySelector("path").getTotalLength() — paste the result into your CSS.

<!-- SVG — a checkmark path -->
<svg viewBox="0 0 24 24" width="40" height="40">
  <path
    class="checkmark"
    d="M4 13 L9 18 L20 7"
    fill="none"
    stroke="#6366f1"
    stroke-width="2"
    stroke-linecap="round"
    stroke-linejoin="round"
  />
</svg>
/* CSS */
.checkmark {
  stroke-dasharray: 22;   /* getTotalLength() result */
  stroke-dashoffset: 22;  /* start hidden */
  animation: draw 600ms ease forwards;
}

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

Pattern 3: Hover State Transition

CSS transitions on SVG properties work exactly like on HTML elements. You can animate fill, stroke, opacity, and transforms on hover with a single transition declaration.

<button class="icon-btn">
  <svg viewBox="0 0 24 24" width="24" height="24">
    <path class="icon-path" d="M12 2L2 7l10 5 10-5-10-5z"/>
    <path class="icon-path" d="M2 17l10 5 10-5"/>
    <path class="icon-path" d="M2 12l10 5 10-5"/>
  </svg>
</button>
/* CSS */
.icon-path {
  fill: none;
  stroke: #A0A0A0;
  stroke-width: 2;
  stroke-linecap: round;
  transition: stroke 200ms ease, transform 200ms ease;
  transform-origin: 50% 50%;
}

.icon-btn:hover .icon-path {
  stroke: #6366f1;
  transform: scale(1.1);
}

Pattern 4: Hamburger → X Toggle

The hamburger-to-close animation is the most common SVG icon state transition in UI. The trick is rotating the outer bars and fading the middle one.

<svg class="hamburger" viewBox="0 0 24 24" width="32" height="32">
  <line class="bar top"    x1="3" y1="6"  x2="21" y2="6"  stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
  <line class="bar middle" x1="3" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
  <line class="bar bottom" x1="3" y1="18" x2="21" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
/* CSS */
.bar {
  transition: transform 300ms ease, opacity 200ms ease;
  transform-origin: 12px 12px; /* center of 24x24 viewBox */
}

/* open state — add .is-open to the <svg> via JS */
.hamburger.is-open .bar.top    { transform: rotate(45deg)  translateY(6px); }
.hamburger.is-open .bar.middle { opacity: 0; transform: scaleX(0); }
.hamburger.is-open .bar.bottom { transform: rotate(-45deg) translateY(-6px); }

Toggle the .is-open class with one line of JavaScript: el.classList.toggle('is-open')

Using CSSVG to Animate Icons Visually

Writing keyframe offsets and transform values by hand gets tedious quickly. CSSVG gives you a visual timeline so you can set keyframes by scrubbing and let the tool output the exact CSS — including easing curves.

  1. 1Import your SVG icon via File → Import SVG. Each sub-path or shape becomes its own animatable layer.
  2. 2Select a layer, drag the playhead to a time, and adjust transform / opacity / fill in the Inspector panel. A keyframe is recorded.
  3. 3Repeat for as many keyframes as needed. The canvas previews the animation live.
  4. 4Export → CSS to get a self-contained SVG + CSS file. Export → SMIL for a fully standalone animated SVG that works in img tags and emails.

Common Gotchas

transform-origin on SVG elements

In SVG, transform-origin is relative to the SVG coordinate system by default, not the element's bounding box. Always set transform-box: fill-box alongside transform-origin to get intuitive center-based rotation.

Inline SVG vs <img> tag

CSS animations only work on inline SVG — SVG loaded via <img src> is sandboxed. Use inline SVG or the SMIL export (which bakes animations into the file itself).

stroke-dashoffset direction

Positive dashoffset shifts the stroke forward (revealing it from the start). Negative shifts it backward. For a left-to-right draw, animate from pathLength → 0.

Animate Your SVG Icons Visually

Skip the hand-coding. Import your icon, set keyframes visually, and export clean CSS in seconds — free, no sign-up.

Open the Editor — it's free