16

I'm trying to animate an SVG circle's radius attribute with CSS. Whilst (using the Firefox Inspect Element tool) I can see that the animation itself is setup and running correctly, the size of the ".innerCircle" doesn't visibly change.

If you can spot anything that I've obviously missed, or help in any way I'd be greatly appreciative. I'm rather new to this, so if I have gone about this wrong, please be kind!

I've pasted my files underneath for reference.

Thanks again.

@keyframes buttonTransition {
  from {
    r: 5%;
  }
  to {
    r: 25%;
  }
}

.innerCircle {
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-name: buttonTransition;
}
<html>
  <head>
    <link href = "styling.css" rel = "stylesheet" type = "text/css"></link>
  </head>
  <body>
    <svg class = "button" expanded = "true" height = "100px" width = "100px">
      <circle cx = "50%" cy = "50%" r = "35%" stroke = "#000000" stroke-width = "10%" fill = "none"/>
      <circle class = "innerCircle" cx = "50%" cy = "50%" r = "25%" fill = "#000000"/>
    </svg>
  </body>
</html>
Nathan Russell
  • 163
  • 1
  • 1
  • 4

4 Answers4

13

In SVG 1.1 the radius of a circle was an attribute and not a CSS property. SVG 2 changes this and instead makes the circle's radius a CSS property that's mapped to an attribute.

CSS animations animate CSS properties and do not animate attributes.

Firefox has now implemented this part of the SVG 2 specification so the testcase in the question will work now although it didn't when the question was written.

SMIL animations will work on attributes (and CSS properties).

<html>
    <head>
        <link href = "styling.css" rel = "stylesheet" type = "text/css"></link>
    </head>
    <body>
        <svg class = "button" expanded = "true" height = "100px" width = "100px">
            <circle cx = "50%" cy = "50%" r = "35%" stroke = "#000000" stroke-width = "10%" fill = "none"/>
            <circle class = "innerCircle" cx = "50%" cy = "50%" r = "25%" fill = "#000000">
              <animate attributeName="r" begin="0s" dur="1s" repeatCount="indefinite" from="5%" to="25%"/>
            </circle>
        </svg>
    </body>
</html>
Robert Longson
  • 118,664
  • 26
  • 252
  • 242
  • 2
    "SVG's SMIL animations (, , etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead." -my console – krummens Dec 07 '16 at 18:24
  • 2
    @krummens presumably a future Chrome update will remove that deprecation warning as they've changed their mind. – Robert Longson Dec 07 '16 at 18:31
  • Seriously? I've done quite a bit of svg with the idea of not being able to use and it's been rough. So I did all that for nothing? – krummens Dec 07 '16 at 18:36
  • 'fraid so. http://stackoverflow.com/questions/40995387/what-is-pure-svg-and-what-is-smil/40995854#40995854 – Robert Longson Dec 07 '16 at 19:06
  • well it's 2020 now and SMIL still has [97%](https://caniuse.com/svg-smil) browser support... – ashleedawg Nov 24 '20 at 07:49
10

There is a simple alternative: animate element scale instead of circle radius. As of 2018, it is supported in Edge and all modern browsers.

SMIL animations is deprecated and only supported by browsers for legacy reasons. It may be dropped in the future and will never appear in Edge or some future browsers.

@keyframes buttonTransition {
    from {
        transform: scale(0.2);
    }
    to {
        transform: scale(1);
    }
}

.innerCircle {
    animation-duration: 1s;
    animation-iteration-count: infinite;
    animation-name: buttonTransition;
    transform-origin: center center;
}
<html>
    <head>
        <link href = "styling.css" rel = "stylesheet" type = "text/css"></link>
    </head>
    <body>
        <svg class = "button" expanded = "true" height = "100px" width = "100px">
            <circle cx = "50%" cy = "50%" r = "35%" stroke = "#000000" stroke-width = "10%" fill = "none"/>
            <circle class = "innerCircle" cx = "50%" cy = "50%" r = "25%" fill = "#000000"/>
        </svg>
    </body>
</html>
Evgeny
  • 6,261
  • 8
  • 35
  • 43
  • SMIL animation may be deprecated but at least there's a polyfill for IE for it. There's no polyfill for CSS animation in IE that I know of. – Robert Longson Jan 04 '17 at 19:15
  • 4
    @RobertLongson It's 2017. Who cares about IE? Edge will soon overtake it in popularity. Besides, CSS animation is IE10+ and nobody supports IE below 11 these days. – Evgeny Jan 04 '17 at 19:28
  • @RobertLongson This is a real bummer. Circle can be faked with border-radius in this particular case. In general, SVG can be replaced with backup png image for IE only and then animated using transforms – Evgeny Jan 05 '17 at 15:57
  • @RobertLongson Just looked into your profile. What's the deal with Firefox transform-origin not applied to SVG elements? It's very, very annoying. Chrome gets it right – Evgeny Jan 05 '17 at 15:58
  • @RobertLongson In other words, it's political. If enough UAa implement it right rather than according to whatever mistaken spec w3c publishes, they will be forced to fix it. – Evgeny Jan 05 '17 at 16:39
  • @RobertLongson [transform-box](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-box) is the solution and it's still in the draft? – Evgeny Jan 05 '17 at 19:07
  • well, it's 2020 now and SMIL still has [97%](https://caniuse.com/svg-smil) browser support... – ashleedawg Nov 24 '20 at 07:49
4

OP query now works out of the box since some browser versions and SVG2 support.

Starting with SVG2, cx, cy, and r are Geometry Properties, meaning those attributes can also be used as CSS properties for that element.

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle

https://svgwg.org/svg2-draft/styling.html#TermPresentationAttribute


This is the same demo defining all the geometry from css. The same cascading rules apply, if a html attributes is declared, it will override stylings from the style attributes, and if a rule is declared in the style attribute, it then override the class rules.

@keyframes buttonTransition {
  from {
    r: 5%;
  }
  to {
    r: 25%;
  }
}

.button {
  width: 30%;
  height: auto
}

.outterCircle {
  cx: 50%;
  cy: 50%;
  r: 35%;
  stroke: #000000;
  stroke-width: 10%;
  fill: none
}

.innerCircle {
  cx: 50%;
  cy: 50%;
  r: 25%;
  fill: #000000;
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-name: buttonTransition
}
<svg class="button">
  <circle class="outterCircle"/>
  <circle class="innerCircle"/>
</svg>
NVRM
  • 11,480
  • 1
  • 88
  • 87
2

If anyone is still looking into how to do this I found a pretty good solution for a filled circle without using SMIL. This solution is a bit of a hack, and it will only work for circles that have a solid fill in them. Essentially what I did was animate the stroke width of these circles to appear as if they are growing.

My original circle

<circle cx="46" cy="46" r="2.8"/>

For this to work I set the radius of the circle to be close to be close to 0.

<circle cx="46" cy="46" r="0.01"/>

Then set a stroke width to be twice the amount of the original radius, and finally setup the animation of the stroke width.

@keyframes circle_animation {
    from {
        stroke-width: 0;
    }
}

circle {
    stroke-width: 5.6;
    animation: circle_animation .5s linear infinite;
}
Bryce Meyer
  • 249
  • 5
  • 9