Set Type on a Circle… with offset-path

Avatar of Chris Coyier
Chris Coyier on

Here’s some legit CSS trickery from yuanchuan. There is this CSS property offset-path. Once upon a time, it was called motion-path and then it was renamed. I sort of rolled my eyes at the time, because the property is so obviously for animating things along a path. But you don’t have to use it for animation, hence the rename, and this example proves it!

The thing with setting elements on a path though, is that the whole element is plopped on that path. So if that element is, say, <span>Chris</span>, that entire word is placed at a single point on the path. yuanchuan’s trick is to break the string into letters-as-spans, then place each span along the path (with a different offset-distance).

There is a top-of-circle path applied to each span:

offset-path: path('M 0 200 A 200 200 0 0 1 400 200')

Then there’s some fancy-dancing math (rather specific to this demo, of course) to calculate appropriate distances for each letter:

offset-distance: calc(8% + var(--n) * 89.5% / var(--total));

The beauty is that each span has its own custom property that affects the calculation. No big-chunk-of-:nth-child repetitive CSS is needed.

<div style="--total:14;">
  <span style="--n:0">C</span>
  <span style="--n:1">S</span>
  <span style="--n:2">S</span>
  <!-- ... -->

And it’s not just for letters! It’s good for all sorts of stuff!

Related notes:

  • This is way cleaner than an old method we blogged where each span had to use transform: rotate() with a common transform-origin point set down away from the letter itself.
  • SVG handles this without any hackery. (This isn’t totally a hack, but since you have to split into spans, you at least need to aria-label the parent, which then makes it feel hackier.)
  • Nitpick (I’m the worst): Don’t just make up HTML tags like this demo Pen on non-demo sites that people need to use.