How to Animate SVG: A Beginner's Guide to CSS and SMIL
A friendly introduction to animating SVG: moving and colouring shapes with CSS, the line-drawing trick, SMIL animation, and when to reach for each approach.
One of SVG's quiet superpowers is that it can move. Because an SVG is real markup living in the page, every shape inside it is something you can animate, spin a loading icon, draw a line as if by hand, pulse a highlight, or morph one shape into another. And you can do a great deal of it with nothing but CSS. This guide starts from zero and builds up the core techniques, so you can add your first SVG animation today.
The mental model: an SVG is a bag of shapes
Before animating anything, hold this idea: an SVG is a container full of individually addressable elements, <circle>, <rect>, <path> and so on. Each is part of the DOM, so each can be targeted by CSS selectors and animated exactly like a <div>. If that idea is new, our intro to what an SVG is explains why SVG shapes are addressable in the first place.
To animate a shape, you need to be able to select it. Give it a class or id:
<svg viewBox="0 0 100 100">
<circle class="dot" cx="50" cy="50" r="20" fill="tomato" />
</svg>
Now .dot is fair game for CSS.
Technique 1: CSS transitions (the easiest win)
The gentlest starting point is a transition on hover or a state change. Suppose you want the circle to grow and brighten when hovered:
.dot {
transform-box: fill-box;
transform-origin: center;
transition: transform 0.3s ease, fill 0.3s ease;
}
.dot:hover {
transform: scale(1.3);
fill: crimson;
}
One quirk to learn early: transform-box: fill-box and transform-origin: center. Without them, an SVG element transforms around the top-left of the whole SVG canvas, not its own centre, and scaling looks like it's flying off. Set those two properties and transforms behave the way you'd expect.
Technique 2: CSS keyframe animations
For continuous motion (a spinner, a pulse) use @keyframes. A classic loading spinner:
.spinner {
transform-box: fill-box;
transform-origin: center;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
Or a soft pulse using opacity and scale:
@keyframes pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.6; transform: scale(1.15); }
}
Keyframes are the workhorse of SVG animation. Anything you can express as a sequence of states over time fits here.
Technique 3: the line-drawing trick
This is the effect that makes people fall in love with SVG animation, a path that draws itself, like an invisible pen tracing a signature or an icon. It relies on two path properties:
.line {
stroke-dasharray: 300; /* roughly the path's total length */
stroke-dashoffset: 300; /* push the whole dash out of view */
animation: draw 2s ease forwards;
}
@keyframes draw {
to { stroke-dashoffset: 0; }
}
The idea: stroke-dasharray turns the stroke into one long dash the length of the path, and stroke-dashoffset initially shifts that dash completely out of sight. Animating the offset to zero reveals the stroke progressively: the line appears to draw itself. You can read the exact path length in JavaScript with path.getTotalLength() so the numbers are precise. This effect only works on stroked paths, so make sure your shape has a stroke and no fill covering it up.
Technique 4: SMIL: animation inside the SVG
Before CSS could do all this, SVG had its own built-in animation language: SMIL. You write the animation inside the SVG using elements like <animate> and <animateTransform>:
<circle cx="50" cy="50" r="20" fill="tomato">
<animate attributeName="r" values="20;28;20" dur="1.5s" repeatCount="indefinite" />
</circle>
That grows and shrinks the radius forever, and it works even when the SVG is used as a standalone file or a background image: a place CSS can't always reach. SMIL's superpower is <animateMotion>, which moves an element along a path, and it can animate attributes (like r) that CSS traditionally couldn't.
The catch: SMIL support has been shaky historically and it's less familiar to most developers than CSS. A reasonable rule: prefer CSS for animations inside HTML pages, and consider SMIL when the SVG must animate as a standalone asset or you need to animate an attribute CSS can't reach.
Getting the values right without the guesswork
The maths (path lengths, keyframe timing, transform origins) is where beginners stall. Rather than hand-tuning dash offsets and durations by trial and error, describe the effect you want in the SVG animation generator and it produces the keyframes and markup for you, running entirely in your browser. It's a fast way to get a working baseline you can then tweak by hand once you understand what each number does. If your SVG came from a design tool, clean it first, our guide on optimising SVG for the web explains why editor cruft can trip up animations by renaming or stripping the IDs you're targeting.
A few things that trip people up
- Animate on a stroked, fillless path for the drawing effect. A fill will hide it.
- Watch your IDs. If an optimiser mangles the IDs your CSS or SMIL references, the animation silently stops. Optimise conservatively for animated SVGs.
- Respect
prefers-reduced-motion. Some users get motion sickness from animation. Wrap continuous effects in a media query so they calm down when the user asks:@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }. - Keep it purposeful. A subtle draw-in or a functional spinner adds polish. A page of shapes wobbling at once is exhausting.
Start with CSS, keep SMIL in reserve
Animating SVG is far more approachable than it looks. Start with CSS transitions for hover effects, graduate to @keyframes for spinners and pulses, learn the stroke-dashoffset trick for self-drawing lines, and keep SMIL in your back pocket for standalone assets. Let the SVG animation generator hand you a working starting point, respect reduced-motion preferences, and animate with a light touch. A single well-judged SVG animation can make an interface feel alive. No video, no heavy library, just shapes and a little time.
A playground for everything above
Each technique in this guide is a preset in the SVG animation generator: spin, pulse, bounce, fade, draw-line and morph, with duration, easing and iteration controls. It shows the animation live and hands you either a self-contained SVG (SMIL inside, works even where stylesheets do not reach) or the plain CSS keyframes, which maps exactly onto the CSS-versus-SMIL decision explained above. Experimenting there is the fastest way to feel the difference between easing curves.
Sources
Written by
Chandrabhan Shekhawat
Founder of Gigai Kripa Services. Builds the 250+ privacy-first browser tools on this site and writes the guides that go with them.
Never miss a guide
New tools and how-to articles land regularly. Follow along however you like. No inbox required.
Keep reading
svg-tools
Understanding SVG Path Syntax: The d Attribute Demystified
The cryptic d attribute in SVG paths (M, L, C, Q, A, Z) explained command by command, with the absolute vs relative rule and how curves actually work.
6 mins readsvg-tools
SVG Data URIs Explained: Inlining Vectors the Efficient Way
What an SVG data URI is, why URL-encoding beats base64 for vectors, and how to inline SVG into CSS and HTML without an extra request, plus when NOT to inline.
5 mins readsvg-tools
Creating Blob and Wave Shapes with SVG for Modern UI
Organic blobs and section-divider waves are everywhere in modern web design. The steps they're built with SVG paths, how to generate them, and how to use them without hurting performance.
5 mins read
Explore related tools
Problems we solve
Definitions
From the blog
- SVG Gradients and Patterns Guide: Linear, Radial, and Seamless Tiles
- SVG Data URIs Explained: Inlining Vectors the Efficient Way
- Creating Blob and Wave Shapes with SVG for Modern UI
- SVG vs Icon Fonts: Which Is Better for Modern Web Icons?
- Using SVG as CSS Backgrounds: Data URIs, Patterns and Crisp Scaling