Skip to main content

So… you can set an SVG circle’s radius in CSS?

By Paul Hebert

Published on January 24th, 2023

But I’m not sure when this became widely supported, and I can’t find anything about it online…

Recently I was working on an animated, circular progress meter:

In order for the stroke animation to work, I needed to do some fancy CSS calculations based on the circle’s radius.

The specific CSS isn’t important, but it’s kinda fun, so if you’re curious, check it out!
///
/// 1. We do some math to determine our circle's circumference. 
///    This gives us the length of the stroke on our circle
/// 2. With more math we can determine how much of our circle's 
///    stroke should be left undrawn (e.g. if our value is 75%, 
///    25% of the stroke should be undrawn. We need this in pixels.)
/// 3. Use SVG stroke drawing to draw the visible part of our stroke
///    @see https://css-tricks.com/svg-line-animation-works/
/// 4. By default, a circle's stroke starts on its right edge. 
///    We want it to start from the top so we rotate the circle.
/// 5. Animate the stroke animation
///
.circle-meter__circle {
  --radius: 47px; // 1
  --pi: 3.14; // 1 - Close enough for our use case!
  --circumference: calc(var(--radius) * 2 * var(--pi)); // 1
  --stroke-length: var(--circumference); // 1
  --stroke-offset: calc(
    var(--circumference) - (var(--circumference) * var(--percent) / 100)
  ); // 2

  rotate: -90deg; // 4
  stroke-dasharray: var(--stroke-length); // 3
  stroke-dashoffset: var(--stroke-offset); // 3
  transform-origin: center; // 4
}

@media (prefers-reduced-motion: no-preference) {
  .circle-meter__circle {
    animation: stroke 750ms both; // 5
  }
}

@keyframes stroke {
  from {
    stroke-dashoffset: var(--stroke-length);
  }
  to {
    stroke-dashoffset: var(--stroke-offset);
  }
}

The important bit is that I needed the --radius property in my CSS to stay in sync with the radius set in my SVG code. But having this value in two different places across two different files made me feel a little itchy. If someone changed the radius later, they’d need to change it in both places, and if they didn’t, it would subtly break the experience.

I knew that you could set some SVG properties in CSS (stroke, fill, stroke-width, and stroke-linecap to name a few.) This made me wonder if I could set the radius using the r property in CSS. So, I tried it out… and it seemed to work! Well, at least in Firefox.

With a bit of trepidation, I started testing in our other supported browsers. It worked in Chrome. It worked in Edge. It even worked in Safari! (And luckily I didn’t have to worry about Internet Explorer.)

I was a little surprised that this worked. My impression was that setting r from CSS was part of the SVG2 draft, but I didn’t think that was supported by any browsers, and VS Code doesn’t seem to like it. But it turns out that setting r is supported in all the browsers I care about?

I knew my colleague Tyler is always down to chat SVGs, so I mentioned it to him and he was also unaware that this was supported. Tyler and I tried to find mention of this new feature on caniuse, MDN, and various browser bug trackers but came up empty.

This leaves me with a lot of questions about what from the SVG2 spec is supported in modern browsers and no clear path to getting answers besides a lot of trial and error.

But, for now, I’m just happy that I can set r from CSS.

Leave a Comment

Please be kind, courteous and constructive. You may use simple HTML or Markdown in your comments. All fields are required.