Self-Drawing Shapes

It looks like a little bit of magic to watch a shape draw itself on the web. Or like it’s probably an embedded video. But it doesn’t have to be! In fact, with remarkably little code and an awfully clever technique involving stroke dashes and offsets, we can do it on any SVG path.

The best shape-drawing tool we have on the web is SVG, and in particular the <path d="" /> element. With the path syntax, you can draw anything you want with its commands for drawing straight and curved lines. A path can be a solid shape, but for our purposes here, let’s assume the path is fill: none; and we’ll focus on the stroke of the path and having that path draw itself.

Let’s say we have a single <path /> that draws a cool shape like this:

In our SVG, we’ll make sure we’ve set up that path nicely like this:

<path 
  pathLength="1" 
  stroke="black"
  stroke-width="5"
  fill="none"
  d="..."
/>

That second line is going to make this trick very easy to pull off, as you’ll see in a moment.

The trick itself, making the shape “draw itself” comes from the idea that strokes can be dashed, and you can control the length and offset of the dashing. So imagine this: you make the dash (and space after the dash) so long that it covers the entire shape, so it appears as if didn’t dash the stroke at all. But then you offset the stroke that far again so that it looks like there is no stroke at all. Then here’s the key: animate the offset so it looks like the shape is drawing itself.

That’s why pathLength="1" is so useful. We’re just animating offset from 1 to 0 which is easy as pie in CSS:

path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: dash 5s linear forwards;
}

@keyframes dash {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

That CSS above will work on any stroked path, assuming you’re using the pathLength trick!

One little problem: Safari. Safari doesn’t like the pathLength attribute on the path, so the easy 1-to-0 trick fails. It’s salvageable though. First, we need to figure out the natural length of the path (rather than forcing it to be 1). We can do that by selecting it in the DOM and:

path.getTotalLength();

In our example above, the length is 8085. So rather than 1, we’ll use that value in our CSS.

path {
  stroke-dasharray: 8085;
  stroke-dashoffset: 8085;

  animation: dash 5s ease-in-out infinite alternate;
}

@keyframes dash {
  from {
    stroke-dashoffset: 8085;
  }
  to {
    stroke-dashoffset: 0;
  }
}

Here’s a fork of the example with that in place, which will work across all browsers. Here’s hoping Safari makes pathLength work though, as it’s far easier to not have to measure path length.

More