Published 12/1/2025 · 6 min read
Tags: svg
Lesson 15: Stroke Animations
The “line drawing” effect — where a path appears to draw itself — is one of the most popular SVG animations. It’s simpler than you might think.
How It Works
The trick uses two properties:
stroke-dasharray— Creates dashed linesstroke-dashoffset— Shifts the dash pattern
If your dash is as long as the entire path, and you offset it by that same length, the path is invisible. Animate the offset to zero, and the path “draws” itself.
Step by Step
1. Create a Path
<svg width="200" height="200">
<path
d="M 20 100 Q 100 20, 180 100"
fill="none"
stroke="black"
stroke-width="3"
class="draw"
/>
</svg>
2. Find the Path Length
You need to know how long the path is. In JavaScript:
const path = document.querySelector(".draw");
console.log(path.getTotalLength()); // e.g., 186.5
Or estimate generously (too long is fine, too short won’t work).
3. Set Up the Dash
.draw {
stroke-dasharray: 200; /* Dash length = path length (or longer) */
stroke-dashoffset: 200; /* Offset by the same amount = hidden */
}
At this point, the path is invisible.
4. Animate the Offset
.draw {
stroke-dasharray: 200;
stroke-dashoffset: 200;
animation: draw 2s ease forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
The path draws itself over 2 seconds!
Complete Example
<svg width="300" height="200" viewBox="0 0 300 200">
<path
d="M 20 180 L 80 50 L 140 120 L 200 30 L 260 100"
fill="none"
stroke="#3b82f6"
stroke-width="4"
stroke-linecap="round"
stroke-linejoin="round"
class="line-chart"
/>
</svg>
.line-chart {
stroke-dasharray: 400;
stroke-dashoffset: 400;
animation: drawLine 1.5s ease-out forwards;
}
@keyframes drawLine {
to {
stroke-dashoffset: 0;
}
}
Reverse Drawing (Erasing)
Animate in the opposite direction:
.erase {
stroke-dasharray: 200;
stroke-dashoffset: 0;
animation: eraseLine 1s ease-in forwards;
}
@keyframes eraseLine {
to {
stroke-dashoffset: 200;
}
}
Or use negative values to draw from the other end:
@keyframes drawReverse {
from {
stroke-dashoffset: -200;
}
to {
stroke-dashoffset: 0;
}
}
Drawing Multiple Paths
Stagger the animations with delays:
<svg width="300" height="200">
<path d="M 50 100 L 150 100" class="line line-1" />
<path d="M 150 100 L 150 50" class="line line-2" />
<path d="M 150 50 L 250 50" class="line line-3" />
</svg>
.line {
fill: none;
stroke: black;
stroke-width: 2;
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: draw 0.5s ease forwards;
}
.line-1 {
animation-delay: 0s;
}
.line-2 {
animation-delay: 0.5s;
}
.line-3 {
animation-delay: 1s;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
Each line segment draws in sequence.
Using SMIL
The same effect without CSS:
<svg width="200" height="200">
<path
d="M 20 100 Q 100 20, 180 100"
fill="none"
stroke="black"
stroke-width="3"
stroke-dasharray="200"
stroke-dashoffset="200"
>
<animate
attributeName="stroke-dashoffset"
from="200"
to="0"
dur="2s"
fill="freeze"
/>
</path>
</svg>
Drawing on Scroll (with JavaScript)
A common effect: paths draw as you scroll down the page.
const path = document.querySelector(".draw");
const pathLength = path.getTotalLength();
// Set up initial state
path.style.strokeDasharray = pathLength;
path.style.strokeDashoffset = pathLength;
window.addEventListener("scroll", () => {
// Calculate scroll percentage
const scrollPercent =
window.scrollY / (document.body.scrollHeight - window.innerHeight);
// Draw based on scroll
const drawLength = pathLength * scrollPercent;
path.style.strokeDashoffset = pathLength - drawLength;
});
Handwriting Effect
For text or signatures, combine with a handwriting-style path:
<svg viewBox="0 0 400 100">
<path
d="M 20 50 C 40 20, 60 80, 80 50 C 100 20, 120 80, 140 50..."
fill="none"
stroke="black"
stroke-width="2"
stroke-linecap="round"
class="signature"
/>
</svg>
.signature {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: write 3s ease forwards;
}
@keyframes write {
to {
stroke-dashoffset: 0;
}
}
Animated Checkmark
A satisfying “task complete” animation:
<svg width="100" height="100" viewBox="0 0 100 100">
<!-- Background circle -->
<circle cx="50" cy="50" r="45" fill="#22c55e" />
<!-- Checkmark -->
<path
d="M 25 50 L 45 70 L 75 35"
fill="none"
stroke="white"
stroke-width="6"
stroke-linecap="round"
stroke-linejoin="round"
class="check"
/>
</svg>
.check {
stroke-dasharray: 80;
stroke-dashoffset: 80;
animation: drawCheck 0.4s ease-out 0.2s forwards;
}
@keyframes drawCheck {
to {
stroke-dashoffset: 0;
}
}
Infinite Drawing Loop
Draw, then erase, repeat:
.loop {
stroke-dasharray: 200;
animation: drawLoop 4s linear infinite;
}
@keyframes drawLoop {
0% {
stroke-dashoffset: 200;
}
45% {
stroke-dashoffset: 0;
}
55% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -200;
}
}
Complex Example: Icon Drawing
<svg width="100" height="100" viewBox="0 0 24 24">
<!-- House icon -->
<path
d="M 3 12 L 12 3 L 21 12 M 5 10 V 20 H 19 V 10"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
class="house"
/>
</svg>
.house {
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: drawHouse 1.5s ease-out forwards;
}
@keyframes drawHouse {
to {
stroke-dashoffset: 0;
}
}
Tips and Tricks
Getting Exact Path Length
document.querySelectorAll("path").forEach((path) => {
console.log(path.getTotalLength());
});
Handling Multiple Segments
If a path has multiple subpaths (multiple M commands), each draws independently. You might need to split them into separate <path> elements for precise control.
Performance
- Stroke animations are GPU-accelerated and performant
- Avoid animating many paths simultaneously
- Consider using
will-change: stroke-dashoffsetfor complex animations
Browser Support
Excellent across all modern browsers. Works on:
- Chrome, Firefox, Safari, Edge
- Mobile browsers
- Even IE11 (for CSS animations; SMIL has issues)
Exercise 15.1: Self-Drawing Logo
Create a simple logo (your initials, a symbol, etc.) using paths, and animate it to draw itself.
Exercise 15.2: Drawing Then Filling
- Draw a shape’s outline first
- Once complete, fade in the fill
Hint: Use animation-delay on a separate fill animation.
Exercise 15.3: Interactive Draw
Create a path that draws when you hover over the SVG, and erases when you hover out.
Exercise 15.4: Scroll-Triggered
Create a line chart that draws as the user scrolls. At 0% scroll, nothing is drawn. At 100% scroll, the full chart is visible.
Key Takeaways
- Line drawing uses
stroke-dasharrayandstroke-dashoffset - Set both to the path length to hide it
- Animate
stroke-dashoffsetto 0 to draw - Use
getTotalLength()to find the exact path length - Stagger delays for multi-path sequences
- Works with CSS animations, transitions, and SMIL