I've never actually used SVG before, which seems like a gap in my knowledge – I'm pretty comfortable with CSS now (see my recreation of a MacOS security modal), and I've tried my hand at Canvas (like this steamy window effect, or the waveform display in my Final Year Project – much more on that to come!). But I've never played with SVG, despite it being pretty much the obvious choice for anything that isn't a photo or a simple geometric shape on the web... maybe I just really hate XML that much?

Anyway – I thought I'd have a go at recreating a button I'd seen on an AWWards-recommended site. Here's how it looks:

The button grows and changes colour, which isn't too hard to create in CSS. The text also changes to an icon, which I decided to leave out – none of the "Material Icons" on CodePen looked right, and I didn't want to have to load in FontAwesome or go hunting for a bespoke icon.

The thing which caught my eye was the ring around the outside – it's not a simple "wipe" from side to side, so (I think) it's beyond the capabilities of CSS animation with a simple DOM element.

In Canvas, this would be a really simple effect to animate – we have the arc command, which lets us give a start and end angle to draw a segment of a circle. I was expecting something similar in SVG, and for a moment there was hope – surely this would have similar options as Canvas?

It was not to be. Although SVG does have a "Path" element, does have an "Arc" command, and does let you specify a rotation for if you're specifying an ellipse, it doesn't let you use angles to specify where the arc starts and ends – you have to use the Cartesian (x, y) coordinates!

I'd like to avoid inserting JavaScript where it's really not needed, but I didn't fancy hardcoding the Polar-to-Cartesian transformation – I needed another way. Luckily, Jake Archibald (of HTTP 203 fame) has a blog post describing just that!

I won't reexplain the blog post here (although if Jake's explanation doesn't work, CSS Tricks also goes over the technique), but the long and the short of it is:

  • Make the line style dashed
  • Make each dash the length of the whole line
  • Offset the dash backwards by the length of the whole line, then animate back to zero

One of the hard bits of this technique is finding the length of the line, but for us that's super easy – it's just the circumference of the circle, and we've already specified the radius in our SVG. Using CSS's calc() syntax we can just multiply that by 2 * 3.1415 to get a more-than-pixel-accurate approximation of the length of the line.

The final step is CSS animating the dash-offset property – to fit with the original we make the transition-timing-function "linear" instead of the default "ease".

For a finishing touch we also rotate the ring 90° anticlockwise so the line-drawing animation starts from the top of the circle.

Here's the relevant CSS:

And the SVG used (just a simple circle):

And here's a codepen to see the finished result: