SVG path animation is a reliable way to deliver crisp, scalable motion without JavaScript. By the end of this article you will build two polished path animations with pure CSS: a signature-style line drawing and a circular check badge. You will learn the small set of CSS properties that make paths “draw” themselves, how to normalize path lengths for predictable timing, how to stagger multiple paths, and how to add tasteful hover effects that respect user motion preferences.
Why Animating SVG Paths with CSS Matters
SVG paths scale to any size, render sharply on every screen, and live right in your HTML. CSS can drive their animation with the same tools you already use for layout and theming. That means no rasterized GIFs, no video files, and no dependency on JavaScript for routine effects like signatures, logos, and progress rings. You get small file sizes, precise control of timing and easing, and styles that integrate with your design tokens. Once you understand stroke-dasharray and stroke-dashoffset, you can stage a drawing effect for almost any outline.
Prerequisites
You do not need an animation library. You should be comfortable editing HTML, targeting classes in CSS, and working with custom properties. A basic feel for SVG structure helps, but this guide provides complete snippets.
- Basic HTML
- CSS custom properties
- CSS pseudo-elements (::before / ::after)
Step 1: The HTML Structure
This project has a container with two inline SVGs. The first draws a curvy signature with two paths. The second is a badge that animates a circular ring and a check mark. Each path declares pathLength=”100″ so the CSS can work with a normalized 0-100 scale for the dash system. That removes the need to measure actual path lengths in JavaScript.
<!-- HTML -->
<div class="wrap">
<h1>CSS-Driven SVG Path Animation</h1>
<section class="panel">
<h2>Signature</h2>
<svg class="sig" viewBox="0 0 200 100" width="400" height="200" aria-hidden="true">
<path class="sig-path stroke-1" d="M10,60 C40,10 65,110 95,60 S150,10 180,60" fill="none" pathLength="100" />
<path class="sig-path stroke-2" d="M10,80 C60,90 120,90 180,80" fill="none" pathLength="100" />
</svg>
</section>
<section class="panel">
<h2>Check Badge</h2>
<svg class="badge" viewBox="0 0 120 120" width="240" height="240" role="img" aria-label="Success">
<circle class="badge-ring" cx="60" cy="60" r="46" fill="none" pathLength="100" />
<path class="badge-check" d="M35 62 L52 78 L85 45" fill="none" pathLength="100" />
</svg>
</section>
</div>
Step 2: The Basic CSS & Styling
Start with a small design system. Use custom properties for ink, accent, and background so the theme is easy to switch. Normalize SVG sizing and give paths a consistent linecap for a polished hand-drawn look. The base rules below do not animate anything yet. They set the canvas for the later keyframes.
/* CSS */
:root {
--bg: #0f1220;
--panel: #161a2b;
--ink: #d8e1ff;
--accent: #6cf3a6;
--accent-2: #7aa7ff;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
color: var(--ink);
background: linear-gradient(180deg, #0b0f1a, var(--bg));
min-height: 100svh;
display: grid;
place-items: center;
}
.wrap {
width: min(900px, 92vw);
padding: 2rem 1rem 3rem;
}
h1 {
font-size: 1.6rem;
margin: 0 0 1rem;
letter-spacing: 0.3px;
}
.panel {
background: var(--panel);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 14px;
padding: 1.25rem;
margin-block: 1rem;
box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}
svg {
display: block;
width: 100%;
height: auto;
}
.sig-path,
.badge-ring,
.badge-check {
stroke-linecap: round;
stroke-linejoin: round;
}
.sig-path {
stroke: var(--ink);
stroke-width: 3;
opacity: 0.95;
}
.badge-ring {
stroke: var(--accent-2);
stroke-width: 8;
}
.badge-check {
stroke: var(--accent);
stroke-width: 8;
}
Advanced Tip: Normalizing with pathLength=”100″ lets you use the same stroke-dasharray and stroke-dashoffset values across paths of different actual lengths. That keeps your keyframes dead simple and timing consistent.
Step 3: Building the Signature Line-Drawing
The signature effect uses the classic dash trick. Set stroke-dasharray to the full virtual length (100), set stroke-dashoffset to the same value so the line is fully hidden, then animate the offset to 0. Stagger multiple strokes with delays for a natural rhythm.
/* CSS */
@keyframes draw {
from { stroke-dashoffset: 100; }
to { stroke-dashoffset: 0; }
}
.sig-path {
/* Hide each path with a 100-long dash and the same offset */
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: draw 2s cubic-bezier(.65,.05,.36,1) forwards;
}
/* Stagger pass two for a convincing signature */
.sig-path.stroke-2 {
animation-delay: 0.35s;
opacity: 0.85;
}
How This Works (Code Breakdown)
Each signature path declares pathLength=”100″. That tells the browser to treat the path as if its total length equals 100 units. The CSS then sets stroke-dasharray: 100, which means one dash that covers the full length, followed by an implicit gap of 0. Setting stroke-dashoffset: 100 shifts that dash entirely past the visible segment, which hides the stroke. The draw keyframes drive the offset down to 0, which rolls the dash into view from the start point along the path.
Using cubic-bezier(.65,.05,.36,1) adds a gentle ease-in and ease-out that suits handwriting. The second path uses animation-delay for a short pause, which prevents both strokes from starting at the exact same time. If you prefer a faster pace, shorten the duration to 1.4s and trim the delay. This technique works on any path: lines, curves, arcs, or complex outlines.
If you want a similar effect without SVG for simple arrows or chevrons, you can build those shapes with pure CSS borders. See how to make an arrow right with CSS for a light alternative when you do not need the precision of a custom path.
Step 4: Building the Circular Check Badge
The badge creates a progress ring that completes and hands off to a check mark. Both elements use the same draw pattern, but with different timings and colors. The ring feels like progress, the check seals the success state.
/* CSS */
@keyframes ring {
0% { stroke-dashoffset: 100; }
60% { stroke-dashoffset: 0; } /* finish the circle earlier */
100% { stroke-dashoffset: 0; }
}
@keyframes pop {
0% { transform: scale(0.96); opacity: 0.6; }
80% { transform: scale(1.04); opacity: 1; }
100% { transform: scale(1); }
}
@keyframes check {
from { stroke-dashoffset: 100; }
to { stroke-dashoffset: 0; }
}
/* Normalize the dash system using the 0-100 pathLength */
.badge-ring,
.badge-check {
stroke-dasharray: 100;
stroke-dashoffset: 100;
transform-box: fill-box;
transform-origin: center;
}
/* Animate the ring first, then give it a subtle pop */
.badge-ring {
animation:
ring 1.4s ease-out forwards,
pop 380ms 1.4s ease-out both;
}
/* Check mark starts after the ring completes */
.badge-check {
animation: check 720ms 1.1s ease-in-out forwards;
}
How This Works (Code Breakdown)
The circle in the SVG is a path under the hood, so it accepts stroke-dasharray and stroke-dashoffset. With pathLength=”100″, the CSS treats 100 as a full revolution. The ring keyframes drive the dashoffset from 100 to 0, which draws the circumference. The check keyframes do the same on the tick mark after a short delay, so your eye sees progress followed by confirmation.
The pop animation scales the ring slightly past 1 and back down to introduce a satisfying settle. transform-box: fill-box and transform-origin: center ensure the scale uses the shape’s own bounding box and center. That keeps the pop clean regardless of viewBox size or SVG scaling. You can tone this down by reducing the scale overshoot or by adjusting the duration.
If you enjoy building decorative badges without SVG, a CSS shape can handle many backgrounds and callouts. For curved badges you can combine rounded rectangles and circles. For straight-edged emblems, try a star: here is how to make a 5-point star with CSS when vector paths are not needed. For circular accents on cards or avatars, review how to make a circle with CSS so you pick the right tool for the job.
Advanced Techniques: Adding Animations & Hover Effects
CSS can layer more polish without changing the SVG. These snippets add hover scrubbing, marquee dashes, and theme-driven color ramps. Use them selectively so motion supports the message.
/* CSS */
/* 1) Hover to scrub the signature "draw" state without keyframes */
.sig:hover .sig-path {
transition: stroke-dashoffset 900ms ease-in-out;
stroke-dashoffset: 0;
}
.sig .sig-path { transition: stroke-dashoffset 600ms ease-in-out; }
/* 2) Marching ants effect for attention (repeatable dash motion) */
@keyframes marching {
to { stroke-dashoffset: -100; }
}
.sig-path.stroke-2.marquee {
stroke-dasharray: 6 8; /* custom dash pattern */
stroke-dashoffset: 0;
animation: marching 1.2s linear infinite;
}
/* 3) Theme swap with CSS variables */
:root.theme-alt {
--accent: #ffd166;
--accent-2: #06d6a0;
--ink: #e0fbfc;
}
The first block replaces keyframes with a simple transition for the signature. The initial rule on .sig .sig-path adds a base transition so the path animates back when the pointer leaves. This gives you a reversible demo interaction without any script. The second block introduces a repeating dash pattern on the second stroke. Setting stroke-dasharray to a pair of values creates a dash-gap cycle, and animating the offset produces a conveyor-belt motion. Use this sparingly to draw focus to active states or to indicate scanning.
For color theming, the .theme-alt class on :root proves that your SVG styles remain dynamic. Because the paths use plain fill and stroke colors, you can plug in tokens from your design system. If your brand has seasonal palettes, you can switch themes with one class on the html element or body.
Pro Tip: If your path feels too slow or too fast after you author the curve, you can edit only the animation duration and keep the same dash values. Normalizing with pathLength avoids re-tuning dasharray values for every shape.
Accessibility & Performance
Path animation should not block content or create barriers. Treat decorative motion as optional flair and productionize it with care for assistive tech and device constraints.
Accessibility
Decorative SVGs should not clutter the accessibility tree. Use aria-hidden=”true” on purely visual graphics like the signature example. For graphics that convey state, give them a role and label. The badge uses role=”img” and aria-label=”Success” so screen reader users get the same feedback as sighted users. If the check indicates a change triggered elsewhere, mirror that state in text nearby.
Honor user motion preferences. Wrap your animation rules in @media (prefers-reduced-motion: reduce) and provide a calmer fallback. This can be as simple as instantly showing the final stroke or removing repeats. Here is a compact pattern:
/* CSS */
@media (prefers-reduced-motion: reduce) {
.sig-path,
.badge-ring,
.badge-check {
animation: none !important;
transition: none !important;
stroke-dasharray: 0; /* draw fully without dashes */
stroke-dashoffset: 0;
}
}
Performance
stroke-dashoffset and stroke-dasharray are cheap to animate on modern engines because they are part of SVG stroke painting, not layout. You can animate dozens of short paths smoothly. Performance drops when you stack expensive filters, blur large vectors, or animate hundreds of long, complex paths at once. Keep filter effects off your animated shapes unless you need them. If you need pulsation, prefer transform: scale() with transform-box: fill-box over repeatedly changing stroke-width, which triggers re-paint of a wider area.
Batch your animations. If several paths start at the same time, give them the same duration and easing so they can land on the same compositor timeline. Avoid toggling classes rapidly with hover on large groups; use a wrapper hover to gate child animations once. For best paint quality, align your SVG viewBox to whole pixel units and keep stroke widths to whole or half pixels to reduce anti-aliasing shimmer.
The last closing paragraph
You now have a practical toolkit for animating SVG paths with CSS: line drawing with dashes, staggered sequences, rings and ticks, and hover scrubbing. These patterns scale from small icons to logo signatures and progress indicators. Explore your library of paths, wire them to these animations, and craft motion that reads clearly at any size.