How SVG line drawing actually works
Every self-drawing icon on the web uses the same trick, and it has nothing to do with drawing. It is a dashed line with one very long dash, slid into view. Once you see it you cannot unsee it.
The dash pattern
stroke-dasharray turns a solid stroke into dashes: the first number is the dash
length, the second is the gap. stroke-dasharray: 10 5 means ten units of ink, five of
nothing, repeated along the path.
Now make the dash as long as the whole path, and the gap just as long:
path { stroke-dasharray: 300 300; } /* 300 = path length */
The path is fully drawn: one dash covers all of it, and the gap falls off the end where nobody can see it.
Sliding it with dashoffset
stroke-dashoffset shifts the whole pattern along the path. Push it by exactly one
path length and the visible dash slides off while the invisible gap slides in:
path {
stroke-dasharray: 300 300;
stroke-dashoffset: 300; /* completely hidden */
}
path.drawn {
stroke-dashoffset: 0; /* completely visible */
}
Animate that one number from 300 to 0 and the line appears to draw itself. That is the entire technique.
Getting the path length
The magic number is the length of the path, which the browser can measure for you:
const path = document.querySelector('path');
const len = path.getTotalLength();
path.style.strokeDasharray = len + ' ' + len;
path.style.strokeDashoffset = len;
If you would rather not run JavaScript, pathLength="1" on the element rescales all
dash values to a 0-to-1 range, so you can write stroke-dasharray: 1 1 and forget the
real geometry.
The complete CSS
<svg viewBox="0 0 24 24">
<path class="draw" pathLength="1" fill="none" stroke="#7c5cff"
stroke-width="2" stroke-linecap="round"
d="M3 12h4l3-9 4 18 3-9h4"/>
</svg>
<style>
.draw {
stroke-dasharray: 1 1;
animation: draw 1.2s cubic-bezier(.45,.05,.55,.95) forwards;
}
@keyframes draw {
from { stroke-dashoffset: 1; }
to { stroke-dashoffset: 0; }
}
</style>
No library, no build step. This is what the animated SVG export produces, with the keyframes worked out for every sub-path.
Where it goes wrong
- One path, several sub-paths. A dash pattern restarts at each sub-path, so a
single
<path>containing three separate shapes draws all three at once, at different rates. Split them into separate elements: each needs its own length. - Round caps and a zero-length dash. With
stroke-linecap: round, a dash of length zero still paints a dot, so at the very start of the animation you get a stray blob. Hide the path until the dash has real length. - The path draws backwards. Direction comes from how the path was authored, not from how it looks. Reverse the path data, or use a tool that can flip it for you.
- Fill ruins it. The shape appears instantly because the fill was never hidden.
Set
fill: none, or animate the fill separately.
Beyond the basic trick
Once the pattern is under your control, other effects fall out of the same two properties. Two dashes of equal length with a gap between them grow from both ends of the path at once. Many short dashes, growing until the gaps close, make the line condense out of a row of dots. A short dash with an offset that keeps moving becomes a comet running along the shape.
All the reveal modes in the editor are variations on those two numbers: open it and watch the dash values change as you switch mode.
Try it as you read. The tool is free and needs no account: open the editor, drop in an SVG and follow along.