SVG animations add motion to a page without video weight or a JavaScript library. Loading spinners, morphing icons, line-drawn logo reveals, animated chart bars: all of those can ship with SVG and CSS alone.
Why SVG beats the alternatives: vector-based, so it stays sharp at every resolution. Lightweight (a simple icon is often under 5 KB). Accessible (every SVG element can carry ARIA). Scriptable (CSS styles SVG the same way it styles HTML).
If you have done CSS animation on HTML elements, you already know 90% of the work. The same @keyframes, animation, and transition properties apply. The only new ideas are SVG-specific properties like stroke-dasharray and stroke-dashoffset that unlock the line-drawing effect.
CSS Transitions on SVG
The minimum case:
`svg
`
`css
.pulse {
transition: r 0.3s ease, fill 0.3s ease;
}
.pulse:hover {
r: 45;
fill: #3b82f6;
}
`
On hover the circle grows and lightens. In SVG, r is a CSS property that can be transitioned.
SVG properties safe to transition:
fill(fill color)stroke(outline color)stroke-width(line thickness)opacityr(radius on circles)cx,cy(center position on circles)transform(rotate, scale, translate)
Usage matches HTML transitions: set the property, the duration, and the easing function. The browser tweens between states.
When the stylesheet ships, run it through the CSS Minifier. Keyframe declarations are verbose; minification often shaves 30-40% off the file.

The Line-Drawing Effect (stroke-dasharray)
The most distinctive SVG trick: a shape that appears to be drawn by an invisible pen. Two properties do the work.
stroke-dasharray: creates dashed lines. Set it to the total path length and the whole path becomes one giant dash.stroke-dashoffset: shifts the dash pattern. At length, the dash is offscreen (path hidden). At 0, it sits over the path (fully visible).
`svg
`
`css
.draw {
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation: draw 2s ease forwards;
}
@keyframes draw {
to { stroke-dashoffset: 0; }
}
`
The path starts hidden (offset = array length) and animates to fully visible (offset = 0). forwards keeps the final state after the animation ends.
For the correct path length, use JavaScript once: document.querySelector('.draw').getTotalLength(). Set both stroke-dasharray and the initial stroke-dashoffset to that value.
This works on any stroked element: path, circle, rect, polygon, text. For sequential reveals, give each path its own animation-delay so the second path starts as the first finishes.
The most distinctive SVG trick: a shape that appears to be drawn by an invisible pen.
Keyframe Animations
@keyframes works on SVG the same way it works on HTML.
Rotating loader:
`css
.spinner {
animation: spin 1s linear infinite;
transform-origin: center;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
`
Pulsing dot:
`css
.pulse {
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { r: 5; opacity: 1; }
50% { r: 10; opacity: 0.5; }
}
`
Color morph:
`css
.morph {
animation: colors 4s ease infinite;
}
@keyframes colors {
0% { fill: #ef4444; }
33% { fill: #22c55e; }
66% { fill: #3b82f6; }
100% { fill: #ef4444; }
}
`
Gotcha: transform-origin defaults to 0 0 (top-left) in SVG, not center as in HTML. Always set transform-origin: center for rotation and scale. For nested elements, transform-box: fill-box makes the origin relative to the element rather than the SVG viewport.
If you also need a subtle background or button highlight to anchor the animation in a card, the CSS Box Shadow Generator and CSS Gradient Generator cover the framing.
Six Patterns Worth Stealing
- Hamburger to X: three
elements. Top rotates 45°, bottom rotates -45°, middle fades. Toggle a class on click. - Progress bar: a
withwidthanimated from 0 to the target value. Addrx="5"for rounded corners. Layer percentage text that updates with the same animation. - Chart bars: multiple
elements withheightanimated from 0, staggered 100 ms apart. Anchor at the bottom by adjustingyasheightincreases. - Wave background: a sine-wave
, duplicated and offset. AnimatetranslateXon each copy at slightly different speeds for parallax. - Checkmark confirmation: a
checkmark animated with stroke-dasharray, on top of a green circle that scales from 0. The classic form-success pattern. - Typing cursor: a
that blinks using opacity with asteps(1)timing function. Pair it with stroke-dasharray text reveal for a typing effect.
All six are pure CSS. No animation library, no framework. Keep the motion subtle and tied to UX. Loading and state transitions: good. Motion for its own sake: distracting.

Performance and Accessibility Rules
Performance:
- Animate
transformandopacitywhenever possible. GPU-accelerated, no layout recalc. Animatingwidth,height,cx,cy, orrforces layout and costs more. - Set
will-change: transformon the elements you plan to animate to hint at compositing layer promotion. - Cap simultaneous animations. More than 10-15 moving SVG elements on screen can drop frames on mid-range phones.
- Run complex SVGs through SVGO before animating. Fewer commands per path means cheaper repaints.
Accessibility:
- Respect
prefers-reduced-motion:
`css
@media (prefers-reduced-motion: reduce) {
.animated { animation: none; }
}
`
- Decorative animated SVGs need
role="img"andaria-label. - Animation should never be the only signal for a state. A spinning loader should also expose
aria-busy="true"or visible text. - Avoid autoplay infinite loops. Constant motion is hostile to users with attention disorders.
- Test in a screen reader. SVGs should either announce meaningfully or be hidden via
aria-hidden.
FAQ
Can SVG paths morph between shapes?
Yes, with caveats. CSS cannot interpolate between arbitrary d values. Both paths must have the same number and type of commands. GSAP and Flubber normalize path data before interpolation, which is why they handle morphing more reliably.
CSS or JavaScript for SVG animation?
CSS for transitions, rotations, color changes, and stroke effects. JavaScript (GSAP, Motion One, Web Animations API) for complex sequences, path morphing, physics-based motion, and anything that needs to respond to user input dynamically.
Why does my SVG animation look different in Safari?
Safari has historical SVG quirks around transform-origin and transform-box. Always test there. Fixes that usually work: add transform-box: fill-box, set explicit pixel transform-origin values, and avoid percentage-based transforms on SVG elements.
How do I shrink an animated SVG?
Run the file through SVGO (svgo.dev) to drop metadata, simplify paths, and clean editor artifacts. Trim unused elements by hand. Move inline styles to CSS classes. Reduce decimal precision on path data. A well-optimized animated SVG is 2-10 KB.
### Can SVG paths morph between shapes.
Markdown Table Generator: Build Clean Tables Without the Pain
Markdown tables are simple until the pipes and dashes stop lining up. Learn the syntax, alignment tricks, and a free tool that formats tables for you.
CSV to JSON: Convert Spreadsheet Data for APIs and Code
Turn a CSV export into clean JSON for APIs, imports, and scripts. Learn how the conversion works, common pitfalls with types and quotes, and a free tool.
JSON Guide: Format, Validate, and Convert JSON Files
JSON guide for developers: syntax rules, common parse errors, formatting and schema validation, plus how to convert between JSON and CSV files.
