Two properties, one idea

An SVG stroke can be drawn as a series of dashes instead of a solid line. stroke-dasharray describes that pattern — the length of each dash and the length of each gap between them. stroke-dashoffset then says how far along the path the pattern starts.

That is the whole model. The array decides the shape of the pattern; the offset decides its position. Because a line has no natural direction except the order of its points, sliding the pattern along it looks exactly like movement.

stroke-dasharray sets the pattern, stroke-dashoffset slides it gap dash dasharray: 12 9  ·  the pattern repeats along the path Moving dashoffset shifts every dash together, so the flow reads as one current.
Figure 1 — Dash and gap make the pattern; the offset moves it. Nothing about the path geometry changes.

The flowing line effect

For a piped flow, keep the pattern modest and march the offset backwards by one full period per cycle. A period is simply the dash length plus the gap length. With a dash of 12 and a gap of 9, the period is 21; animating the offset to -42 means two full periods have passed, so the loop is seamless.

.flow {
  stroke-dasharray: 12 9;   /* dash + gap = 21 period */
  stroke-dashoffset: 0;
  animation: travel 1.15s linear infinite;
}

@keyframes travel {
  to { stroke-dashoffset: -42; }  /* 2 × 21 */
}

Why the negative sign matters

A decreasing offset pulls the pattern towards the start of the path, which the eye reads as forward motion. Reverse the direction of travel by flipping to a positive offset. Keep every arrow in one diagram moving the same way unless the system genuinely reverses, otherwise readers dilute the signal.

The self-drawing path effect

The same two properties draw a path on instead of shaking a flow through it. Set one dash longer than the whole path and one gap longer than the path, then animate the offset from the full path length down to zero. The line appears to sketch itself from start to finish.

.draw {
  stroke-dasharray: 600;   /* ≥ path length */
  stroke-dashoffset: 600;  /* hidden at the start */
  animation: draw 1.6s ease-out forwards;
}

@keyframes draw {
  to { stroke-dashoffset: 0; }
}
Self-drawing path: one dash, offset animated to zero 65% drawn dashoffset: 415 → 0 the outline grows until the ring closes Use a value at least as long as the path length so the whole stroke hides at the start.
Figure 2 — A dash as long as the path, hidden by the offset, draws on as the offset falls to zero.

Pitfalls worth knowing

  • Period mismatch. If your trip distance is not a whole number of periods, the loop visibly snaps. Multiply the period.
  • Path length unknown. For hand-written paths, use getTotalLength() in a console one-liner to find the exact value for a perfect draw-on.
  • Too much at once. Combining dashoffset with scale, blur and rotation buries the point. One moving property is enough.
  • Forgetting reduced motion. Wrap every offset keyframe so it can be disabled; the still path should always remain legible.
Bottom line: flow and self-drawing are not different techniques — they are the same two properties with different numbers. Learn the period once and you can animate any system diagram.