Shots in this scene
Drawing Lines
In one line
A line draws itself when its stroke is one dash as long as the path and the dash is slid into view with stroke-dashoffset. pathLength="1" makes that length 1 for every path, and three traps (round caps, gaps in the path, dashed strokes) need known fixes.
Think of it like this
A garden hose lying on the lawn with a long sleeve of paint on it, the sleeve exactly as long as the hose. Slide the sleeve off the far end and the hose is bare. Slide it back and the hose appears, starting from the near end. Drawing a line in SVG slides a dash along the path like that sleeve.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- stroke
- The outline of a shape, or the line of a path. Its colour is
strokeand its thicknessstroke-width. A path withfill: noneis only a stroke. - stroke-dasharray
- The pattern of drawn and empty lengths along a stroke.
1alone means 1 drawn, 1 empty, repeating. - stroke-dashoffset
- How far the dash pattern is slid backwards along the path. Offset equal to the dash length moves the first dash out of sight.
- pathLength
- An attribute that tells the browser to treat the path as this many units long for dashing, so a dash of 1 always means the whole path.
- getTotalLength()
- A method of path elements: the real length in user units. It ignores the
pathLengthattribute. - stroke-linecap
- The shape of the stroke's ends:
butt(flat, the default),roundorsquare. A round cap draws a dot even for a dash of length 0. - mask
- An SVG element that hides parts of whatever uses it: white parts show, black parts hide.
Step by step
01Draw the route
Press Draw again on "A route drawing itself". The console says getTotalLength(): 385.20, pathLength attribute: 1, dasharray 1px, resting dashoffset 0px. Pause at 0.1× and step: the Web Animations track is stroke-dashoffset, 1400 ms, ease-in-out, with an amber (paint) cost mark.
02Read the offset at the half way point
Pause at 700 ms. The stroke-dashoffset track's graph is at 0.5 and half of the line is drawn. ease-in-out is symmetric, so the middle of the time is the middle of the line.
03Find the dot
In "Why a rounded number leaves a dot" the first box (A) is empty, the second (B) shows a dot at the start of the line, and the third (C) shows one too. The console says why: 0.20 of a dash starts B, and C has a dash of length 0 with a round cap.
04Compare two pieces and a dashed line
Press Draw in "Two pieces and a dashed line". Pause at 300 ms: in the top row both pieces have grown by 60 units. In the middle row only the first piece is drawn, and the second waits for its 450 ms delay. The blue dashed line grows with the mask.
Try it yourself
- 1
Remove pathLength
In the first example delete
pathLength="1"from the<path>and press Draw again. Pause at 700 ms: the full line is already on screen andstroke-dashoffsetreads 0.5. The line never draws, because1is now a 1-unit dash on a path 385 units long. - 2
Make B clean
In the second example change
#b's offset from384.8to385: the dot at the start of B goes. Then putpath { stroke-linecap: butt; }at the end of the CSS: B and C show nothing either, because a flat-ended dash of 0.2 units, or of length 0, has no visible area. - 3
Reorder the pieces
In the third example change the delay of
p2from450to0. Both middle pieces now grow together, like the top row. The top row is one path, so it can never do the sequence.
Code & diagrams
The resting state is the finished line. The animation starts from offset 1 (empty) and ends at 0.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
getTotalLength(): 385.20 user units
pathLength attribute: 1
dasharray 1px, resting dashoffset 0pxRound caps make any dash with length, or none, show as a dot. Press **Draw A** to draw the clean one. The button uses `fill: "forwards"` only so the demo stays drawn; Topic 8.4 says why the project should not.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
the path is 385.20 long
A (offset 385): the whole line is in the gap, nothing shows
B (offset 384.8): 0.20 of a dash starts the line, so a round cap shows
C (dasharray 0): a zero-length dash still gets a round capRow one: one path, two pieces, drawn together. Row two: two paths, the second delayed by 450 ms. Row three: a dashed line uncovered by a mask whose path draws.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
one path, two pieces: total 200 = 90 + 110Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Hide the dashed line's mask with the default units
In the third example delete maskUnits="userSpaceOnUse" x="0" y="0" width="300" height="120" from the <mask> and press Draw.
Break #2
Hide with a rounded offset
In the second example set #a { stroke-dashoffset: 384.8; } (it is 385 now).
Myth vs fact
Myth
You must call getTotalLength() and write the number into the CSS.
Fact
Only without pathLength. With pathLength="1" every path uses 1 and 0, in CSS alone.
Myth
A path with several pieces draws like one line.
Fact
The pattern restarts on each piece, so they draw together. Use one path per piece, with delays.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
The dash trick draws a path by length, so easings apply to the length: with
ease-inthe line starts slowly and the end rushes. For a route that follows the scroll (Topic 13.6) uselinear, so the line tracks the finger. - ▸
stroke-dasharray: 0 12with round caps draws a row of dots (the dot of box C), and a mask uncovers it like a dashed line.
Remember this
- 1
The problem this solves: CSS cannot animate "how much of a line is drawn". There is no
draw: 50%. But every stroke can be made of dashes, and the dash pattern can be moved. That is enough to draw a logo, a route or a signature, with no JavaScript and no video. - 2
The two properties.
stroke-dasharraysets the pattern of dash and gap lengths, for example10 4(10 drawn, 4 empty, repeating).stroke-dashoffsetslides the pattern backwards along the path by that distance. Make one dash as long as the whole path (stroke-dasharray: L) and then offset it byL: the dash has slid off the start and the line looks empty. Animate the offset fromLto 0 and the line draws from its start to its end. - 3
**
pathLength="1"removes the measuring.**getTotalLength()gives the real length in user units: 385.20 for the route in the first example. You would have to measure every path and write that number in the CSS. The attributepathLength="1"tells the browser to treat the path as 1 unit long, whatever it is really, and dash lengths then use that scale. Now every path usesstroke-dasharray: 1and an offset from 1 to 0.getTotalLength()still says 385.20, because it ignores the attribute. In the project, keep the resting state drawn (stroke-dashoffset: 0) and animate only from 1, so that a browser or a user that skips the animation shows the finished line. - 4
Rounded caps draw a dot. With
stroke-linecap: round, any dash that has length, even a tiny one, gets round ends. In the second example the path is 385.20 long. Dash 385 with offset 385 hides everything, but offset 384.8 leaves 0.20 of a dash at the start and a round cap shows as a dot. A dash of length 0 (stroke-dasharray: 0 400) shows a dot too, andstroke-linecap: buttshows nothing for the same values. Hide with an offset equal to the dash, and preferpathLength="1", so no rounded number can be off by a little. - 5
**Without
pathLength,1is one unit of a very long path.** Withstroke-dasharray: 1the line is 1 drawn and 1 empty over 385 units, and a 5-unit round stroke fills the gaps: the line is there all the time and never draws (tryIt 1). - 6
Gaps in the path. A path with two pieces (
M20 20 H110 M170 20 H280) is measured as one length: 200, which is 90 plus 110. But the dash pattern restarts at every piece. One offset therefore draws both pieces at once, each from its own start. To draw them in turn, use one<path>per piece and delay the second by the length of the first (450 ms of a 1000 ms draw in the third example: 90 is 45 percent of 200). - 7
Dashed strokes cannot use the trick, because the dash pattern is already used for the dashes. Draw a solid path inside a
<mask>instead and give the real dashed linemask="url(#reveal)". The mask path draws and the dashed line is uncovered as it grows. SetmaskUnits="userSpaceOnUse"with a real size: the default mask area is the box of the element that uses it, and a horizontal line has no height (breakIt 1). - 8
Measuring needs no screen, drawing does.
getTotalLength()gave 242.48 for one test curve in the page, inside<defs>and inside adisplay: nonegroup, and 0 for a path that is onlyM20 20or has an emptyd: a length of 0 means nothing to draw, not an error. Adisplay: nonepath shows no dash at all. - 9
On the timeline.
stroke-dashoffsetmeasured as paint (amber): the browser draws the stroke again on each frame, on the main thread. That is fine for a logo or one route, but it cannot be pushed to the compositor liketransform. Do not draw 200 lines at once on a phone without checking the track and the frame strip.
Explain it without notes
How does the stroke-dasharray and stroke-dashoffset trick draw a line, and why does pathLength="1" help?
Why does a round-capped line show a dot before it starts to draw, and how do you prevent it?
Practice
Draw a path #underline under a heading once, in 600 ms with ease-out, with a finished line as the resting state and no drawing for reduced motion.
A logo has two separate pieces (a ring and a bolt) in one <path>. Draw them one after the other.
Done when you can
You can draw a line with
stroke-dasharray,stroke-dashoffsetandpathLength="1"You can say why a round cap shows a dot and how to hide the line cleanly
You can draw two pieces in sequence and a dashed line with a mask
You know the draw costs paint on the timeline