I bet all of you have seen that little trick where an SVG path is animated to look like it’s drawing itself. It’s super cool. Jake Archibald pioneered the technique and has a super good interactive blog post on how it works. Brian Suda wrote about it on 24 Ways. Polygon used it to great effect on a custom-designed article and wrote about it. Codrops has some neat examples.
I have very little to add, except my brain just kinda figured it out, so I thought I would explain it one more time the way it clicked for me.
1. You have an SVG shape
2. The shape must have a stroke
3. Strokes can be dashed
We could do that from Illustrator, but we can also do it programmatically. Let’s target the path with CSS (assuming we’re using inline SVG here, or via an <object>
) and apply the dash that way.
<svg ...>
<path class="path" stroke="#000000" ... >
</svg>
.path {
stroke-dasharray: 20;
}
That gives us dashes of 20px in length.
4. Those dashes could be longer…
.path {
stroke-dasharray: 100;
}
5. We can also “offset” the stroke, which moves the position of those dashes
Watch as we animate the offset of those long strokes:
That was a simple as:
.path {
stroke-dasharray: 100;
animation: dash 5s linear;
}
@keyframes dash {
to {
stroke-dashoffset: 1000;
}
}
6. Imagine a dash so long it covers the entire shape
Nothing really to see, it looks just like the complete shape if it wasn’t dashed at all. You just need to make stroke-dasharray
a longer value than the length of the stroke.
7. Now offset that stroke so that instead of covering the entire shape, it NOT covers the entire shape.
It will look like the shape isn’t there at all.
8. Now animate the stroke offset back to 0
If doing it with CSS, you’ll want the animation to have animation-fill-mode
of forwards
so the final state remains how the animation ends.
.path {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 5s linear forwards;
}
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
Tada!
Live Example
So why all the JavaScript?
Most of the examples you see of SVG line animations use JavaScript. That’s because it’s hard to know what the length of that stroke actually is. We just used 1000
in our example because that happens to be about the right length.
You can get that length in JavaScript like:
var path = document.querySelector('.path');
var length = path.getTotalLength();
Then use it however you will. Those articles I linked to at the top go far more into all this, so I’ll let you consult those for more fancy stuff. I just wanted to cover the concept so perhaps it can click for you too.
There is a trick as well! Check out A Trick That Makes Drawing SVG Lines Way Easier.
Great article, thanks for this!
Nice!
I could not get the total length from non-paths. So I made a little thing to convert all the non-paths into paths first and then calculating the lengths and animating.
I’m using it on my wedding-website http://10-5.de/
You can see the code on my pen: http://codepen.io/niorad/pen/xmfza
Wow, that is a really cool wedding website and an excellent example of what can be done with SVG animation.
Many congratulations for the wedding and the website is really nice.
Bravo!
As always, using properties for effects they were never intended for :)
Totally sweet. Such a simple method that could be used to produce some great effects!
Very cool, but alas, no Internet Explorer support. Not even IE11.
Then no SVG animations for IE. Create a fallback solution!
I’ve found the only way to get good cross browser support was using Javascript to animate for IE9 and greater. Here’s a good reference to get started -> Animating SVGs
I also found that this doesn’t work in IE. Snap.svg is a pretty great alternative. All the techniques and basic theory here hold true; you create a
path
with a given length, and then setstrokeDasharray
andstrokeDashoffset
to the same length. Then you can just dopath.animate({strokeDashoffset: 0}, 1000);
for the same effect (1000 is time in ms).Very nice! I made an experiment using it. But to work in chrome I had to add
@-webkit-keyframes
and-webkit-animation
.You can see it here.
I’m having trouble understanding this part:
“Now offset that stroke so that instead of covering the entire shape, it NOT covers the entire shape.”
If you make the dash array equal to the length of the stroke, why does offsetting it make it begin to disappear where does the rest of it go?
Yeah that is weird. I guess it’s because when you do the dash thing, there always has to be at least one dash and one gap of equal length. So depending on where that dash or gap line up, is what portion of the stroke appears to be filled in.
Setting
stroke-dasharray: 1000;
is just shorthand for settingstroke-dasharray: 1000 1000;
, i.e., a 1000-pixel dash followed by a 1000-pixel gap. From the specs:Hello Chris
I was just playing around the code and when I run it my system (after copy pasting the code) i was not able to get any output on the screen.
but what added more to my surprise was that it runs smoothly on code pen but not on jsbin or js fiddle.
(http://jsfiddle.net/65LzR/ “fiddle”)
please delivery your views on it
browser used : chrome 32
It looks like the animation is properly initialising. By popping it open in chrome and toggling the animation property. It then runs correctly.
Hey there,
It’s because the current version of chrome requires the -webkit- prefix for the css animations
so it’d be “-webkit- animation: and @-webkit-keyframes”
http://jsfiddle.net/SeKLe/ – Here’s a fork of your demo with the prefixes added.
Awesome tutorial, thank you for sharing.
That’s awesome!
This is great! Thanks. Do you have any resources/docs for svg properties that can be animated using css (or even js, for example in combination with the amazing greensock animation library?.
This beats the hell out of what I’m currently using; the getSubpath() method in Raphael.js. It did the job, but often looked more like the stroke was being scaled up from its origin point.
Hi!
That’s very nice!!
It works if I write the svg in html, but it doesn’t if I import the svg using the object:
I can this be fixed?
:*
If you hide your SVG in an
<object>
tag, it’s inaccessible from CSS. You could include the CSS styles inside the external SVG file, but I can’t guarantee that will work in all SVG browsers.yay! great article, one question: how can I stop the animation once are finished?
animation-fill-mode: forwards;
Amazing! Thanks a lot for this quick and easy-to-understand explanation!
Thanks a load! It’s really useful.
Great ! :)
Just a heads up that not all browsers interpret the
stroke-dashoffset
property the same way, and the way you’re defining the animation could cause unexpected results. See this Stack Overflow Q&A.I’m not quite sure how the offset is getting interpretted in those cases, but the specs really aren’t very specific about what should happen when the dash pattern is twice the length of a closed path and you start with the pattern offset the entire length. The end effect is that some browsers interpret the switch to a zero offset as going from a fully-stroked line to nothing, and some interpret it as going from nothing to fully stroked. Which doesn’t make much difference if you’re setting the animation to
alternate infinite
, but it makes a big difference if you want to draw the line and leave it there.I would recommend doing the entire animation with the
stroke-dasharray
property:Fork of the example Pen with changes implemented.
And with the animation made one-way only.
Yeah it makes for some pretty cool and easy animations especially if your designer loves vector and won’t work in anything except adobe illustrator.
Will that value be “static”, meaning will it always be the same for the same given path? So that it would be enough to use JS once to get its length, and then one could put that fixed value into the CSS (yeah, I know, it’d be kind of a ”magic number”, but still).
Or is it dynamic, depending on … what? Browser, display size of the SVG image, …?
The length is given in the coordinate system units for the path element, and therefore is independent of any scaling of the SVG as a whole. However, the specs allow browsers to guesstimate the exact length using an algorithm of their choosing, so the results might not always be exactly the same. To control for that, you can set the “pathLength” attribute on your path element to the value that you’re using for animations, and the browser is supposed to adjust its calculations accordingly.
In other words, to ensure inter-operability you can use Javascript to figure out the length of your path on your development computer, and then declare that length in a
pathLength
attribute on the path element, and then safely use it in your CSS animations without worrying that things will be slightly off on a different browser. You could skip the calculation and just declare the pathLength to be a nice round number of your choosing, but then you’d want to do some in-depth cross-Browser testing to make sure they all make the appropriate calculations…Thanks Amelia, also for your other comment, quite useful!
Hi,
I recreated this and I would like after the animation is drawn to stay on the page. How would I go about that? I took out the infinite and it only plays once. I would like it to stay on the page.
Any help would be great.
Thanks!
.path {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
-webkit-animation: dash 5s linear;
-webkit-animation-iteration-count:1;
}
@-webkit-keyframes dash {
from {
stroke-dashoffset: 1000;
}
to {
stroke-dashoffset: 10;
}
}
I don’t get it, why do you need stroke-dashoffset: 1000;?
You can just do this:
.path {
stroke-dasharray: 1000;
animation: dash 5s linear;
animation-fill-mode: forwards;
}
@keyframes dash {
from{
stroke-dashoffset: 1000;
}
to {
stroke-dashoffset: 0;
}
}
Some browsers support SVG but not the line animation (I’m looking at you IE).
So how can I test if the browser supports SVG line animation, so I can fallback to a raster ?