SVG Animation Basics
A practical introduction to SVG animation covering CSS transitions, keyframes, transforms, SVG attributes, SMIL, path animation, JavaScript interaction, and performance.
SVG animation allows vector graphics to change over time. Shapes can move, rotate, scale, change color, appear or disappear, and even morph into different shapes. Because SVG elements can participate in the browser's DOM and CSS system, developers can combine SVG with CSS animations, transitions, JavaScript, and SVG-specific animation features.
SVG animation is useful for interactive icons, loading indicators, charts, illustrations, maps, diagrams, logos, and visual feedback. It can range from a simple hover transition on an icon to complex animations involving paths and multiple coordinated elements.
This guide focuses on the fundamentals developers need to understand before building more advanced SVG animations.
How SVG Animation Works
An SVG graphic consists of elements such as path, circle, rect, line, polygon, and text. These elements have attributes that describe their geometry and appearance. Animation works by changing those properties over time.
<svg
viewBox="0 0 100 100"
width="100"
height="100"
>
<circle
class="circle"
cx="50"
cy="50"
r="20"
/>
</svg>For example, changing the circle's cx value moves it horizontally. Changing r changes its radius. Changing fill changes its color. CSS and JavaScript can control these changes, while animation systems determine how the values change over time.
The Main Ways to Animate SVG
There are several approaches to SVG animation in modern web applications. CSS transitions and keyframes are usually the simplest options for interface graphics. JavaScript is useful when animation depends on application state or user input. SVG's SMIL animation system can animate SVG attributes directly and remains useful for certain graphics.
| Approach | Best suited for | Main advantage |
|---|---|---|
| CSS transitions | Simple state changes | Easy to implement |
| CSS keyframes | Repeated or multi-step animation | Declarative timeline |
| JavaScript | Interactive and dynamic animation | Full application control |
| SMIL | SVG-specific attribute animation | Works directly with SVG attributes |
| Web Animations API | Programmatic browser animations | JavaScript control with browser animation infrastructure |
Animating SVG with CSS Transitions
CSS transitions are useful when an SVG changes from one state to another. A common example is an icon changing color or rotating when a button enters a hover state.
.icon {
transition:
transform 200ms ease,
fill 200ms ease;
}
.icon:hover {
transform: rotate(45deg);
fill: #4f46e5;
}<svg
class="icon"
viewBox="0 0 24 24"
width="48"
height="48"
>
<path
d="M5 12h14M12 5v14"
fill="none"
stroke="currentColor"
stroke-width="2"
/>
</svg>Transitions work particularly well for small interface interactions because they only need a starting state and an ending state.
SVG Transforms
Transforms allow an SVG element to move, rotate, scale, or skew without changing its underlying geometry. Common transform operations include translate, rotate, scale, and skew.
.icon {
transform: rotate(0deg);
transition: transform 300ms ease;
}
.icon:hover {
transform: rotate(180deg);
}Transforms are often preferable to changing an element's geometric coordinates for simple visual movement. They can also be combined to create more complex effects.
Transform Origin
The point around which an element rotates or scales is important. CSS provides transform-origin for controlling this point.
.arrow {
transform-origin: center;
transition: transform 200ms ease;
}
.arrow.is-open {
transform: rotate(180deg);
}For SVG, transform behavior can also depend on the element's coordinate system and the browser's handling of the SVG viewport. When an animation appears to rotate around an unexpected point, inspect the transform origin and the SVG geometry.
CSS Keyframe Animations
CSS keyframes are useful when an animation contains multiple stages or should run independently of a hover or other state transition.
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.15);
opacity: 0.7;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.loader {
animation: pulse 1.2s ease-in-out infinite;
}<svg
class="loader"
viewBox="0 0 100 100"
width="80"
height="80"
>
<circle
cx="50"
cy="50"
r="30"
/>
</svg>The animation property controls the duration, timing function, repetition, and other animation behavior.
Animation Timing
The timing function controls how quickly an animation progresses between keyframes. Common options include linear, ease, ease-in, ease-out, and ease-in-out.
.linear {
animation: pulse 1s linear infinite;
}
.smooth {
animation: pulse 1s ease-in-out infinite;
}Timing has a major effect on how an animation feels. A linear movement maintains a constant rate, while easing creates acceleration and deceleration.
Animating SVG Colors
SVG fills and strokes can be animated when the browser can interpolate the corresponding values.
.status {
fill: #64748b;
transition: fill 250ms ease;
}
.status.is-active {
fill: #22c55e;
}For icons, it is often useful to use currentColor instead of hardcoding the SVG color. The surrounding CSS can then control the color through the color property.
.icon {
color: #64748b;
transition: color 200ms ease;
}
.icon:hover {
color: #4f46e5;
}Animating Opacity
Opacity is one of the simplest SVG properties to animate. It is useful for fading elements in and out or creating subtle visual emphasis.
.notification-icon {
opacity: 0;
transition: opacity 200ms ease;
}
.notification-icon.is-visible {
opacity: 1;
}Opacity animations can be combined with transforms to create effects such as an element fading in while moving into position.
Animating SVG Paths
Paths are among the most powerful SVG elements for animation. Their stroke can be animated to create drawing effects, while their geometry can also be manipulated for more advanced animations.
.draw-path {
fill: none;
stroke: currentColor;
stroke-width: 4;
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation: draw 1.5s ease forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}The stroke-dasharray property creates a dash pattern, while stroke-dashoffset changes where that pattern begins. With suitable values, the effect can make a path appear to be drawn over time.
The SVG Path Drawing Effect
The exact dash length required for a drawing animation depends on the path's length. A common technique is to set stroke-dasharray and stroke-dashoffset to approximately the same value as the path length.
const path = document.querySelector(".draw-path");
if (path instanceof SVGGeometryElement) {
const length = path.getTotalLength();
path.style.strokeDasharray = String(length);
path.style.strokeDashoffset = String(length);
}After setting the initial values, CSS can animate stroke-dashoffset toward zero. This technique is useful for signatures, line illustrations, charts, and icon animations.
Animating SVG Geometry
SVG elements have geometric attributes such as cx, cy, r, x, y, width, and height. Some of these can be animated using CSS or SVG animation mechanisms, depending on the property and browser behavior.
.circle {
transition:
cx 300ms ease,
r 300ms ease;
}
.circle.is-expanded {
r: 40px;
}For many interface animations, CSS transforms are simpler than changing geometry. Geometry animation becomes especially useful when the shape itself needs to change rather than simply move or scale.
Animating SVG with SMIL
SMIL is a set of XML-based animation features historically associated with SVG. SVG elements can contain animation elements such as animate, animateTransform, and animateMotion.
<svg
viewBox="0 0 100 100"
width="100"
height="100"
>
<circle
cx="20"
cy="50"
r="10"
>
<animate
attributeName="cx"
from="20"
to="80"
dur="1.5s"
repeatCount="indefinite"
/>
</circle>
</svg>This animation changes the circle's cx attribute over time without requiring CSS or JavaScript.
SMIL can be useful when the animation is naturally expressed in terms of SVG attributes. However, CSS and JavaScript are often easier to integrate with modern application state and frontend architecture.
animateTransform
The animateTransform element is designed specifically for animating SVG transforms.
<rect
x="25"
y="25"
width="50"
height="50"
>
<animateTransform
attributeName="transform"
type="rotate"
from="0 50 50"
to="360 50 50"
dur="2s"
repeatCount="indefinite"
/>
</rect>The values define the rotation angle and its center point. This can be useful for self-contained SVG files that should animate without application code.
Animating Along a Path
SVG can also describe motion along a path. SMIL provides animateMotion for this type of animation.
<path
id="motion-path"
d="M10 80 C30 20 70 20 90 80"
fill="none"
stroke="none"
>
<animateMotion
dur="3s"
repeatCount="indefinite"
>
<mpath href="#motion-path" />
</animateMotion>
</path>In practice, path-based motion is often easier to implement with CSS motion-path or JavaScript when the animation needs to integrate tightly with an application.
JavaScript-Controlled SVG Animation
JavaScript becomes useful when the animation depends on application state, pointer movement, scrolling, data, or other runtime conditions.
const circle = document.querySelector(".circle");
let position = 20;
function move() {
position += 1;
if (circle instanceof SVGCircleElement) {
circle.setAttribute("cx", String(position));
}
if (position < 80) {
requestAnimationFrame(move);
}
}
requestAnimationFrame(move);The requestAnimationFrame API schedules animation work in synchronization with the browser's rendering cycle. It is generally preferable to repeatedly changing visual properties with setInterval when building custom JavaScript animation loops.
CSS vs JavaScript for SVG Animation
| Requirement | CSS | JavaScript |
|---|---|---|
| Simple hover transition | Excellent fit | Usually unnecessary |
| Looping loading animation | Excellent fit | Usually unnecessary |
| Multiple animation stages | Keyframes work well | Possible |
| Animation based on application state | Possible | Useful for complex logic |
| Pointer-driven animation | Limited | Strong fit |
| Scroll-driven custom behavior | Possible with modern CSS features | Useful for complex behavior |
| Dynamic data visualization | Limited | Strong fit |
| Complex interaction | Can become difficult to manage | More flexible |
Animating SVG in React
In React applications, SVG can be animated with ordinary CSS classes, component state, CSS transitions, keyframes, or animation libraries. For simple interface animations, CSS is often enough.
import { useState } from "react";
export function ToggleIcon() {
const [active, setActive] = useState(false);
return (
<button
type="button"
onClick={() => setActive((value) => !value)}
>
<svg
className={active ? "icon is-active" : "icon"}
viewBox="0 0 24 24"
aria-hidden="true"
>
<path d="M5 12h14" />
</svg>
</button>
);
}.icon {
transform: rotate(0deg);
transition: transform 200ms ease;
}
.icon.is-active {
transform: rotate(45deg);
}The component controls state, while CSS controls the visual transition. Keeping those responsibilities separate often produces simpler React code.
SVG Animation and Hover States
Hover animations are common for interface icons, buttons, links, and navigation elements. A small movement or color change can provide visual feedback without requiring JavaScript.
.download-icon {
transition:
transform 180ms ease,
color 180ms ease;
}
.download-link:hover .download-icon {
transform: translateY(3px);
color: #4f46e5;
}For touch devices, do not rely on hover as the only way to communicate an important state. The interface should still work and communicate meaning without hover-specific behavior.
SVG Animation and User Interaction
SVG elements can respond to clicks, pointer events, keyboard interaction, and application state. For interactive graphics, it is important to distinguish visual animation from the actual interaction logic.
<button
type="button"
aria-expanded="false"
class="menu-button"
>
<svg
class="menu-icon"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path d="M5 7h14M5 12h14M5 17h14" />
</svg>
Menu
</button>The button should provide the semantic interaction, while the SVG animation can visually communicate the state change. This is preferable to making an SVG shape itself the only interactive control when a standard HTML element can provide the required semantics.
Animating SVG Paths with CSS Variables
CSS custom properties can make SVG animations configurable without duplicating entire animation definitions.
.progress-path {
--progress: 0;
stroke-dasharray: 100;
stroke-dashoffset: calc(100 - var(--progress));
transition: stroke-dashoffset 400ms ease;
}<path
class="progress-path"
d="M10 50a40 40 0 1 0 80 0a40 40 0 1 0-80 0"
/>In a real progress indicator, the dash values should account for the actual path length. CSS variables can then provide a convenient interface between application state and the visual representation.
Animating Stroke Properties
Stroke properties can produce useful visual effects. Besides stroke-dasharray and stroke-dashoffset, properties such as stroke width and line caps can influence the appearance of an animation.
.line {
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
transition:
stroke-width 200ms ease,
opacity 200ms ease;
}
.line:hover {
stroke-width: 4;
opacity: 0.8;
}Animating Fill and Stroke Together
SVG elements can combine fill and stroke animations. This is useful for highlighting shapes, emphasizing selected regions, or creating visual state changes.
.shape {
fill: transparent;
stroke: #64748b;
transition:
fill 250ms ease,
stroke 250ms ease;
}
.shape.is-selected {
fill: #dbeafe;
stroke: #2563eb;
}Performance Considerations
SVG animation can be efficient, but performance depends on what is being animated and how complex the SVG is. Animating a small icon is very different from animating thousands of SVG elements in a large visualization.
For simple movement, transforms and opacity are often good starting points. Animating layout-related properties or repeatedly performing expensive JavaScript calculations can create unnecessary rendering work.
Complex SVG filters, masks, large numbers of nodes, and frequent geometry updates can also increase the browser's rendering workload.
Avoid Animating Too Many Elements
An SVG illustration can contain hundreds or thousands of elements. Animating every element independently can create substantial rendering work.
If a complex illustration only needs to move as a single unit, wrapping the relevant elements in a group and animating the group can be much simpler.
<svg viewBox="0 0 200 100">
<g class="illustration">
<circle cx="50" cy="50" r="20" />
<rect x="80" y="30" width="40" height="40" />
</g>
</svg>.illustration {
transform: translateX(0);
transition: transform 400ms ease;
}
.illustration.is-moved {
transform: translateX(30px);
}Reduced Motion
Some users prefer reduced motion because animation can be distracting or uncomfortable. Websites should respect the user's prefers-reduced-motion preference for non-essential animations.
.loader {
animation: pulse 1.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
.loader {
animation: none;
}
}Not every animation must disappear completely. In some interfaces, replacing continuous motion with a simpler state change or a short transition can preserve useful feedback while reducing motion.
Animation Duration
Animation duration should match the purpose of the interaction. Small interface feedback usually needs a relatively short duration, while an illustration or decorative animation can use a longer timeline.
There is no single correct duration for every SVG animation. The important considerations are whether the animation communicates a state change, provides feedback, or is purely decorative.
Animation Fill Modes
CSS animation-fill-mode determines which styles apply before and after an animation. The forwards value is especially useful when the element should keep the final keyframe state after the animation finishes.
.success-icon {
animation: reveal 400ms ease forwards;
}
@keyframes reveal {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}Delays and Staggered SVG Animations
Animation delays can create staggered effects when multiple SVG elements should appear one after another.
.bar {
animation: rise 500ms ease forwards;
opacity: 0;
}
.bar:nth-child(1) {
animation-delay: 0ms;
}
.bar:nth-child(2) {
animation-delay: 100ms;
}
.bar:nth-child(3) {
animation-delay: 200ms;
}This technique can be useful for charts, loading indicators, illustrations, and decorative sequences.
Animating SVG with the Web Animations API
The Web Animations API provides a JavaScript interface for creating and controlling browser animations. It can be useful when animation needs runtime control without manually updating properties on every animation frame.
const icon = document.querySelector(".icon");
icon?.animate(
[
{ transform: "rotate(0deg)" },
{ transform: "rotate(180deg)" },
],
{
duration: 400,
easing: "ease",
fill: "forwards",
}
);The API also provides controls such as play, pause, reverse, and cancel. This can be useful for application-driven animation where CSS alone becomes cumbersome.
SVG Animation in External Files
SVG animation is not limited to inline SVG. An SVG file can contain its own animation definitions and can be displayed as an external resource.
However, the way the SVG is embedded affects what the surrounding HTML can control. An SVG loaded through img is isolated from the parent document's DOM, so page-level CSS and JavaScript cannot directly manipulate its internal elements.
If the animation is entirely self-contained, an external animated SVG can still be useful. If the animation needs to react to application state, inline SVG or another integration strategy is generally more convenient.
Common SVG Animation Mistakes
- Animating complex geometry when a transform would produce the same visual effect.
- Using JavaScript for simple hover transitions that CSS can handle.
- Animating hundreds of SVG elements independently without measuring performance.
- Forgetting to provide a reduced-motion experience.
- Making important interface state depend only on animation.
- Using hover as the only way to trigger an important interaction.
- Animating an external SVG with page CSS and expecting to reach its internal elements.
- Using very long or continuous animations without a clear purpose.
- Changing many SVG attributes on every animation frame when a browser-managed animation could perform the same effect.
- Ignoring accessibility semantics because an SVG is visually decorative.
A Practical SVG Animation Workflow
Start with the visual state you want to communicate. Decide which SVG properties actually need to change and whether the animation is triggered by hover, focus, a component state change, user input, or a timeline.
For simple state changes, start with a CSS transition. If the animation contains multiple stages or repeats independently, use CSS keyframes. If the animation requires application logic, consider JavaScript or the Web Animations API. For self-contained SVG attribute animations, SMIL can also be appropriate.
Finally, test the animation on different screen sizes and devices, check its accessibility behavior, respect reduced-motion preferences, and measure performance if the SVG is complex.
Choosing the Right Animation Technique
| Scenario | Recommended starting point |
|---|---|
| Icon color change | CSS transition |
| Icon rotation | CSS transform and transition |
| Looping loader | CSS keyframes |
| Path drawing effect | stroke-dasharray and stroke-dashoffset |
| Animation based on React state | CSS classes or transitions |
| Pointer-driven animation | JavaScript or Web Animations API |
| Complex data visualization | JavaScript or a visualization library |
| Self-contained SVG animation | SMIL or CSS inside the SVG |
| Animation along a path | CSS motion features, SMIL, or JavaScript depending on requirements |
Frequently Asked Questions
Can SVG images be animated with CSS?
Yes. Inline SVG elements can be styled and animated with CSS transitions and keyframes. CSS can animate supported SVG-related properties as well as transforms, opacity, and other visual properties.
What is the easiest way to animate an SVG?
For simple interface animations, CSS transitions are usually the easiest starting point. CSS keyframes are useful for repeated or multi-step animations.
Can SVG paths be animated?
Yes. A common technique uses stroke-dasharray and stroke-dashoffset to create a path-drawing effect. JavaScript can calculate the path length with getTotalLength when the exact length is not known in advance.
Should I use CSS or JavaScript for SVG animation?
Use CSS for straightforward visual transitions and keyframe animations. JavaScript is useful when animation depends on application state, user input, data, or more complex runtime logic.
What is SMIL in SVG?
SMIL is an XML-based animation system associated with SVG. Elements such as animate and animateTransform can modify SVG attributes over time without JavaScript.
Can external SVG files be animated?
Yes. An SVG file can contain its own animation. However, when loaded through img, its internal elements are isolated from the parent document, so page-level CSS and JavaScript cannot directly control them.
How can I make SVG animations accessible?
Provide appropriate semantic HTML, avoid making important information depend only on animation, and respect prefers-reduced-motion. Interactive graphics should also provide usable keyboard and assistive-technology interactions where applicable.
Helpful SVG Animation Tools
An SVG Viewer is useful for checking the final appearance of an animated asset, while an SVG Formatter makes complex SVG markup easier to inspect. A CSS Animation Generator can help build keyframe animations, and a CSS Transform Generator is useful when an SVG effect relies on rotation, translation, scaling, or other transforms. For path-based animations, an SVG Path Editor can make it easier to inspect and modify the geometry that will be animated.
Conclusion
SVG animation is built around changing the properties of vector elements over time. CSS transitions are a simple solution for state changes, CSS keyframes work well for repeated and multi-step animations, and JavaScript provides more control when animation depends on application logic or user interaction. SMIL remains another option for animations that naturally map to SVG attributes.
For most frontend interfaces, start with CSS and only introduce JavaScript when the animation actually requires runtime control. Use transforms and opacity where appropriate, keep complex SVGs under control, and test animations on realistic devices.
Finally, treat animation as part of the interface rather than an isolated visual effect. Respect reduced-motion preferences, preserve meaningful semantics, and make sure important information or functionality remains understandable without relying on animation alone.