Command Palette

Search for a command to run...

Hectal
Shots in this scene
SHOT 13.3Intermediate ~22 min · shot 3 of 6

Motion Along a Path

In one line

offset-path gives an element a track, offset-distance says how far along it is, and offset-rotate turns it to face the way it travels. The path's numbers are in CSS pixels for an HTML element and in user units for an SVG shape.

0/6 · 0%

Think of it like this

A toy train on a track. You do not tell the train its x and y at every moment. You say how far along the track it is, and the track decides where it is and which way it faces, even round bends.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

offset-path
The track an element follows, written as path("…") with the same text as an SVG d attribute, or url(#id) for an SVG shape.
offset-distance
How far along the track the element is, from 0% (the start) to 100% (the end of an open path).
offset-rotate
How the element turns on the track: auto faces along the path, an angle keeps a fixed turn, auto 90deg combines both.
tangent
The direction a curve points at one spot. offset-rotate: auto turns the element to the tangent.
open path
A path that does not end where it started. Past 100% an element on it stays at the end.

Step by step

01Read where the dots sit

"An HTML dot and an SVG circle" prints three points: the middle of the route on screen (183, 47), the SVG circle at 50% (184, 48), and the HTML dot at 50% (91, 24). The script sets offset-distance: 50% on both, reads the boxes, and clears it again.

02Ride it

Press Ride. Two offset-distance tracks run for 2000 ms. Pause at 1000 ms and step: the orange circle travels along the line, and the blue HTML dot travels along the same shape at half the size, in the top-left corner.

03Turn the arrow

In "An arrow on a path that crosses itself" press Ride and pause at 1500 ms: the arrow sits on the upward leg, pointing up. Press Turn and ride again to see 0deg and auto 90deg: both point right at that spot.

04Check the crossing

The console prints the path length 306.27, the two distances 18.5% and 81.5%, and the same screen point for both blue dots: (71, 61).

Try it yourself

  1. 1

    Fix the HTML dot's scale

    In the first example change the SVG to width="150" height="60" and the .wrap to the same size. The drawing is no longer scaled, so the HTML dot and the circle both land within one pixel of the middle of the route: (91, 24) and (92, 25). Change the script's two * 2 to * 1 to print the middle at the same scale (the console line still says 2x, but it now prints 91, 24).

  2. 2

    Overshoot

    In the second example change the 100% in the Ride animation to 150% and ride. Pause at 2900 ms: the arrow is at the end of the path, pointing down and to the left along the last leg. It does not wrap round.

  3. 3

    Slow it to a crawl at the crossing

    Pause the second example and step through 18.5% and 81.5% of the ride: the arrow passes the same point twice, once heading down-right and once heading down-left. Nothing in the animation knows it is the same point.

Code & diagrams

An HTML dot and an SVG circle on one route

The same path text on both. The drawing is shown at twice its size. The HTML dot rides in unscaled pixels.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

middle of the route on screen: 183, 47 (the drawing is shown at 2x)
SVG circle at 50%: 184, 48
HTML dot at 50%: 91, 24
An arrow on a path that crosses itself

Press Ride, then use Turn to try `auto`, `0deg` and `auto 90deg`.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

path length 306.27, crossing reached at 18.5% and again at 81.5%
first pass at 71, 61, second pass at 71, 61

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Break the path text

In the second example change #arrow's offset-path: path("M30 20 …") to path("L30 20 L110 100 L110 20 L30 100"), with no M.

terminal
$ Look at the arrow and press Ride
── what you'll see ──
The arrow sits in the top-left corner of the drawing, half cut off, and stays there. There is no error in the console.

Myth vs fact

Myth

The path inside offset-path scales with the SVG, like the path I can see.

Fact

Only on an SVG shape. An HTML element reads CSS pixels, so a drawing shown at 2× leaves it at half the distance (measured: (91, 24) instead of (183, 47)).

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The track itself is not drawn by offset-path. If the route should be visible, draw the same path as a normal stroke (Topic 13.2) and make the two share one string, so they cannot drift apart.

  • ▸

    An offset-distance track is amber: measured in headless Chromium, it repaints every frame but needs no layout. Cheap for one dot; check the track for a hundred.

  • ▸

    A dot that rides a route that is also drawing should sit at an offset-distance equal to the draw progress. Both are length fractions, so one scroll timeline can drive both (Phase 12).

Remember this

  1. 1

    The problem this solves: moving something along a curve used to need JavaScript maths or a chain of keyframes. Three properties do it: offset-path (the track), offset-distance (how far along, from 0% to 100% of the track's length) and offset-rotate (which way the element faces). You animate only offset-distance.

  2. 2

    **offset-path: path("M10 50 C40 5 …")** takes the same path text as an SVG d attribute. Reuse the text of the drawn route so the element rides the line you see. On an SVG shape Chromium also accepts offset-path: url(#route): in a test the dot sat 0.1 units from the real midpoint.

  3. 3

    The coordinate trap. For an HTML element the path's numbers are CSS pixels. For an SVG shape they are user units, so they scale with the viewBox. In the first example the same path text is used on both, with the drawing shown at 2×. The middle of the route is at (183, 47) on screen, the SVG circle at 50% sat at (184, 48), and the HTML dot at (91, 24): half, because its path was not scaled. Over a scaled drawing, scale the numbers yourself, or ride an SVG shape inside the drawing.

  4. 4

    A shape is placed by its own (0, 0). An SVG shape rides with its coordinate origin on the path, so draw it around (0, 0): the circle has no cx and the arrow is M-8 -6 L10 0 L-8 6 Z. An HTML element is placed by its centre (its transform origin) by default.

  5. 5

    **offset-rotate.** auto turns the element so its x axis points along the path. 0deg keeps its own angle. auto 90deg is auto plus 90 degrees, for a shape drawn pointing up. On the upward leg of the second example, auto points the arrow up, and both 0deg and auto 90deg point it right.

  6. 6

    Crossing paths and the ends. offset-distance counts length, not position, so a path that crosses itself is no problem: the crossing of the second example's X shape is reached at 18.5 percent and again at 81.5 percent, and two dots placed at those distances sat at the same screen point, (71, 61). On an open path a distance above 100% stays at the end (tryIt 2).

  7. 7

    A wrong path fails silently. A path text that does not parse makes the whole declaration invalid, and the browser drops it without a message: the arrow stays at the top-left corner, although the timeline still lists an offset-distance track (breakIt).

Explain it without notes

01

Why does an HTML dot miss the route when the SVG is scaled, but an SVG circle does not?

02

What does offset-rotate: auto do, and when do you use auto 90deg?

Practice

01

Make a small circle #bike ride the route #route forever in 4 seconds, linear, and stop for reduced motion at the end of the route.

02

A paper plane drawn pointing up should follow a curve and face the way it flies. What do you write?

Done when you can

  • You can animate an element along a path with only offset-distance

  • You can say why an HTML element misses a scaled drawing

  • You can pick auto, a fixed angle or auto 90deg

  • You know a bad path is ignored without an error