The d Attribute Structure
An SVG path is a string of commands, each followed by its parameters. Commands are single letters; parameters are space- or comma-separated numbers:
<path d="M 10 10 L 90 10 L 90 90 L 10 90 Z" />
Reading left to right: move to (10,10), line to (90,10), line to (90,90), line to (10,90), close. Result: a square.
Absolute vs Relative Commands
Uppercase commands use absolute coordinates. Lowercase commands use coordinates relative to the current position:
/* Absolute — exact coordinates */
M 10 10 L 100 50 L 150 10
/* Relative — offset from current position */
M 10 10 l 90 40 l 50 -40
/* Both produce the same path */
Relative commands produce shorter path strings when you're drawing repeating patterns or incremental shapes. Absolute commands are clearer when you want specific coordinates (e.g., aligning to a grid).
Path Commands Reference
| Command | Parameters | Purpose |
|---|---|---|
| M / m | x y | Move to (no line drawn) |
| L / l | x y | Line to |
| H / h | x | Horizontal line to (y unchanged) |
| V / v | y | Vertical line to (x unchanged) |
| C / c | x1 y1 x2 y2 x y | Cubic Bezier (two control points) |
| S / s | x2 y2 x y | Smooth cubic Bezier (reflects previous control) |
| Q / q | x1 y1 x y | Quadratic Bezier (one control point) |
| T / t | x y | Smooth quadratic Bezier |
| A / a | rx ry rot arc sweep x y | Elliptical arc |
| Z / z | (none) | Close path back to last M |
Cubic Bezier Curves
The cubic Bezier command C x1 y1 x2 y2 x y describes a curve from the current point to (x, y). The curve's shape is determined by two control points that "pull" the curve in their direction:
<path d="M 10 90 C 30 10, 70 10, 90 90" stroke="white" fill="transparent"/>
/* Wave from (10,90) to (90,90) bulging upward */
/* Control points: (30,10) pulls curve up at start, (70,10) pulls up at end */
Visualization: imagine the control point attached to the endpoint by an invisible rubber band. The curve leaves each endpoint heading toward its control point, then bends smoothly to the other endpoint.
To make a wave go down instead of up, swap the control point Y values below the baseline: C 30 170, 70 170, 90 90.
Smooth Curve Chains
The S command continues a smooth curve by automatically calculating the first control point as a reflection of the previous curve's last control point:
/* Wavy line using C then S */
M 10 50
C 30 10, 50 10, 70 50
S 110 90, 130 50
S 170 10, 190 50
The S command only needs the second control point and the endpoint — the first control point is inferred from the previous curve. This guarantees a smooth transition (no visible corner) between connected curves.
Arc Command (Circles & Ellipses)
The arc command A rx ry rotation largeArc sweep x y is the most complex, but powerful for rounded corners and arcs:
/* Half circle from (10,50) to (90,50) */
M 10 50 A 40 40 0 0 1 90 50
/* Parameters:
* rx ry — radii of the ellipse
* rotation — x-axis rotation in degrees
* largeArc — 0 or 1, use large or small arc
* sweep — 0 or 1, clockwise (1) or counter-clockwise (0)
* x y — endpoint */
Full circle requires two arc commands since a single arc can't trace a full 360° (starting and ending at the same point is ambiguous). Usually easier to use the <circle> element for circles.
Path Optimization for File Size
Hand-coded paths are typically already compact. Paths exported from design tools (Figma, Illustrator, Sketch) often have redundant decimals and absolute coordinates:
/* Before SVGO: */
M 10.000000 10.000000 L 90.000000 10.000000 L 90.000000 90.000000 Z
/* After SVGO: */
M10 10 90 0v80z
Use an SVG optimizer (SVGO, online tools, or build-step plugins) to:
- Remove unnecessary decimals (3 decimals is enough for visual quality)
- Convert absolute to relative commands where shorter
- Merge sequential commands (
M 10 10 L 20 20 L 30 30→M 10 10 L 20 20 30 30) - Use
HandVfor horizontal/vertical lines instead ofL - Remove whitespace between commands where unambiguous
Animating SVG Paths
Two CSS techniques animate SVG paths without any JavaScript:
Path Drawing Effect
.path-draw {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: draw 3s ease forwards;
}
@keyframes draw {
to { stroke-dashoffset: 0; }
}
Start with a dash gap the length of the path, then animate the offset to zero — the path appears to draw itself. Get the path's actual length with path.getTotalLength() in JavaScript for precise values.
CSS Motion Path
.moving-object {
offset-path: path('M 10 10 L 90 90 L 10 90 Z');
offset-distance: 0%;
animation: move 4s linear infinite;
}
@keyframes move {
to { offset-distance: 100%; }
}
Moves an element along any SVG path. Useful for animated icons, loading indicators, and decorative effects.
Frequently Asked Questions
- Can I use pixel values in SVG paths?
- Path coordinates are unitless — they refer to the SVG's coordinate system defined by
viewBox. If your viewBox is0 0 100 100, coordinates range 0–100 regardless of the SVG's display size. The SVG scales to fit its container automatically. - How do I morph one path into another?
- CSS transitions on the
dattribute work in modern browsers (transition: d 0.5s), but only if both paths have the same number and type of commands. For more complex morphs, use libraries like Flubber, GSAP MorphSVG, or anime.js — they interpolate between different path structures. - Why is my path filled when I only want a stroke?
- SVG paths fill by default. Add
fill="none" stroke="black"attributes to get stroke-only. Or set via CSS:path { fill: none; stroke: currentColor; }. Usestroke-widthto control thickness. - What's the difference between <path> and <polygon>?
<polygon>only supports straight lines between points.<path>supports curves too.<path>is a strict superset — any polygon can be expressed as a path, but the reverse isn't true.- Can I convert an image to an SVG path?
- Yes, via tracing tools (Inkscape's Trace Bitmap, Vectorizer.ai, Potrace). They produce paths approximating the image's outlines. Results work well for logos and simple illustrations; photos become lossy abstractions. For detailed images, raster formats are usually better.