How to control `transform-box` for `<use>` elements? - css

Background
I’m loving the expanded CSS support in SVG2. It’s great not having to rewrite attributes over and over. So I’ve been converting some code in a project from SVG attributes to CSS. Most of this has worked just fine.
When it comes to transforms, things can seem tricky if you are comfy with how CSS transforms work in HTML. (This is especially true for rotate() transformations, which is the focus of this question.) That’s because SVG doesn’t have the “automatic flow” that HTML does.
In other words, when you have a bunch of HTML elements, one after another, they will automatically lay themselves out according to the box model.
There is no such “automatic” or “default” layout in SVG. As a result, SVG transforms default to being calculated from the origin. (That’s 0,0 in user coordinates).
The Almost-Perfect Solution
For most elements, there’s a simple solution: the awesome CSS property transform-box. In most cases, using the following CSS will allow you to transform SVG elements in pretty much the same way as HTML elements:
/* whatever elements you want to transform */
rect, polygon {
transform-box: fill-box;
transform-origin: center center; /* or `top left`, `center right`, etc. */
}
.rotate90 {
transform: rotate(90deg);
}
Now, you can just do something like...
<rect class="rotate90" x="123" y="789" width="50" height="50" />
And it will rotate around the transform-origin specified in the CSS. Since the above example used a transform-origin of center center, it rotates in place.
That matches the behavior of HTML elements using transform: rotate(…). And—especially if there’s a lot of rotations like this in an SVG image—it is way, way better than the equivalent SVG markup.
Why is CSS better than the SVG markup equivalent?
Because SVG’s rotate() function has a slightly different syntax that does not have an equivalent to the transform-box: fill-box CSS used above, unless you specify an X and Y coordinate for every rotation.
That means you have to put in the rotation point every time, like so:
<rect x="123" y="789" width="50" height="50"
transform="rotate(90 123 789)"
></rect>
<!--
In this example, the rotation pivots around the X and Y coordinates of the `rect` element.
If you wanted to rotate around the center, you would have to calculate:
x + width/2
y + width/2
And use those values in the `rotate()` function instead.
-->
The Problem
The problem I’ve run into is that the CSS solution does not work with <use /> elements.
It’s pretty clear why: the <use /> element clones the referenced element into a new location. So, as far as the CSS is concerned, it is transforming the <use /> element, and not the cloned (Shadow-DOM) content.
When it comes to other challenges involving applying CSS to <use />—such as setting up different color schemes—there are solutions (like this one from SVG superhero Sara Soueidan).
But when it comes to getting around the issue of coordinates, I haven’t figured out a way around this.
Example Code
EDIT: To be more explicit about what I’m going for, here is some sample code.
.transform-tl,
.transform-tc,
.transform-tr,
.transform-cl,
.transform-cc,
.transform-cr,
.transform-bl,
.transform-bc,
.transform-br {
transform-box: fill-box;
}
.transform-tl { transform-origin: top left; }
.transform-tc { transform-origin: top center; }
/*
…and so on, for the other combinations of `transform-origin` keyword values…
*/
.rotate90.cw {
transform: rotate(90deg)
}
.rotate90.ccw {
transform: rotate(-90deg)
}
<!--
Using the CSS classes in the following manner works as intended for most SVG elements as intended.
But with the `<use />` element, the rotation does not pivot around the top left corner, as expected... :(
-->
<use
class="transform-tl rotate90 cw"
x ="0"
y ="1052"
href ="#block-A12-2"
></use>
(Thanks to #PaulLeBeau for the nudge to include this bit of code.)
Does anyone have a solution?
(Even a workaround solution—as long as it involves less repetition than specifying the SVG transform attribute on every <use />—would be welcome!)

Assuming the same conditions as #Sphinxxx postulated...
Then you can also just wrap your <use> element in a group (<g>) element and apply the rotate class to that.
/* whatever elements you want to transform */
rect, polygon, use, g {
transform-box: fill-box;
transform-origin: center center; /* or `top left`, `center right`, etc. */
}
.rotate45 {
transform: rotate(45deg);
}
<svg width="300" height="200">
<defs>
<rect id="rr" x="80" y="60" width="50" height="50" />
</defs>
<use href="#rr" x="100" y="0" fill="tomato" />
<g class="rotate45">
<use href="#rr" x="100" y="0" fill="lime" />
</g>
</svg>
What's going on? Why does this work?
The reason has to do with how <use> elements are dereferenced and what happens to transforms when that happens. If you read the section about <use> elements in the SVG spec, it says:
In the generated content, the ‘use’ will be replaced by ‘g’, where all attributes from the ‘use’ element except for ‘x’, ‘y’, ‘width’, ‘height’ and ‘xlink:href’ are transferred to the generated ‘g’ element. An additional transformation translate(x,y) is appended to the end (i.e., right-side) of the ‘transform’ attribute on the generated ‘g’, where x and y represent the values of the ‘x’ and ‘y’ attributes on the ‘use’ element.
So, the following SVG (which I presume will be something like you were trying):
<use href="#rr" x="100" y="0" fill="lime" class="rotate45" />
will be dereferenced into the equivalent of:
<g fill="blue" transform="rotate(45) translate(100,0)">
<rect x="80" y="60" width="50" height="50" />
</g>
Since you can think of transforms as being applied from right to left, the translate(100,0) will be applied before the rotation, meaning that the rotation will be moving something that is offset 100 pixels away from where you want it. That's why the transform-box: fill-box is not working for <use> elements.
rect, polygon, use, g {
transform-box: fill-box;
transform-origin: center center; /* or `top left`, `center right`, etc. */
}
.rotate45 {
transform: rotate(45deg);
}
<svg width="300" height="200">
<defs>
<rect id="rr" x="80" y="60" width="50" height="50" />
</defs>
<use href="#rr" x="100" y="0" fill="tomato" />
<use href="#rr" x="100" y="0" fill="blue" stroke="blue" class="rotate45" />
<g fill="lime" transform="rotate(45) translate(100,0)">
<rect x="80" y="60" width="50" height="50" />
</g>
</svg>
However with my solution, the <g> + <use> set...
<g class="rotate45">
<use href="#rr" x="100" y="0" fill="lime" />
</g>
will be dereferenced into the equivalent of:
<g class="rotate45">
<g fill="lime" transform="translate(100,0)">
<rect x="80" y="60" width="50" height="50" />
</g>
</g>
rect, polygon, use, g {
transform-box: fill-box;
transform-origin: center center; /* or `top left`, `center right`, etc. */
}
.rotate45 {
transform: rotate(45deg);
}
<svg width="300" height="200">
<defs>
<rect id="rr" x="80" y="60" width="50" height="50" />
</defs>
<use href="#rr" x="100" y="0" fill="tomato" />
<g class="rotate45">
<use href="#rr" x="100" y="0" fill="blue" stroke="blue"/>
</g>
<g class="rotate45">
<g fill="lime" transform="translate(100,0)">
<rect x="80" y="60" width="50" height="50" />
</g>
</g>
</svg>
In this version, each of the two transform operations is applied to different elements, so the transform-box and transform-origin are applied separately. And the transform origin has no effect on translations.
So what that means is that the transform-box calculation for the rotation (ie on the <g>) will be applied to the already-translated object. So it will behave as you want.
In the days before transform-box, these two examples would have given the same result.

So you want to put an element somewhere with <use x="..." y="...", and then rotate it in place?
The simplest solution I have found does include the transform attribute, but you don't need to specify the rotation point. See the following example, where the green rectangle does what you want.
In CSS, we include use elements in the transform-box rule. Then we position and rotate each element with the transform attribute (replacing x, y and CSS rotation):
/* whatever elements you want to transform */
rect, polygon, use {
transform-box: fill-box;
transform-origin: center center; /* or `top left`, `center right`, etc. */
}
.rotate45 {
transform: rotate(45deg);
}
<svg width="300" height="200">
<rect id="rr" x="80" y="60" width="50" height="50" />
<use href="#rr" x="100" y="0" class="rotate45" fill="tomato" />
<use href="#rr" transform="translate(100 0) rotate(45)" fill="lime" />
</svg>

Related

SVG scale by (100% - 60px)

I'm trying to build an SVG image with content that is 100% the width of the container, minus 60px for some text.
If I was using HTML, or SVG with javascript, I would have no problem doing this. But I feel like there should be a way to do this using SVG (and CSS if needed).
I want the equivalent of this (Codepen here):
<svg width="100%" height="100%">
<rect fill="#ccc" x="0" y="0" width="100%" height="100%"></rect>
<text x="100%" y="50%" stroke="black" text-anchor="end">Y-axis</text>
<svg width="100%" height="100%">
<!-- This rect represents the entirety of the contents of the graph -->
<rect x="0" y="0" style="width: calc(100% - 60px)" height="100%" fill="#c88"></rect>
</svg>
</svg>
In the above snippet, the inner <rect> resizes to be 100% - 60px the width of the container element. However, this trick only works for a single element - if you replace that <rect> with a complex SVG structure it no longer works.
Things I've tried:
Doing a transform: scale() via CSS on the <rect> - I can't figure out what to put into the scale() to make it behave like 100% - 60px.
Changing the width of the nested <svg> element
<svg width="calc(100% - 60px)"> doesn't work - can't do calc() inside the width attribute
<svg width="100%" style="width: calc(100% - 60px);"> (with or without the width attribute) - doesn't work - the CSS "width" property is ignored whether or not the width attribute is present.
I'm starting to think what I want to do isn't possible right now with SVG, but it doesn't seem like an uncommon use case. Is there any way to do this?
As discussed in the comments, you might have some luck achieving the same by making your graph area 100% of the viewBox, but place the SVG in a container with 60px of padding on the right to account for the text space.
Moving your text (and background rect) to x="100%" with its text-anchor="start", in addition to letting the SVG overflow, you can get a pretty close result without needing to transform your graphic, since you have a fixed 60px value you can consistently rely on:
div {
padding-right: 60px;
}
svg {
overflow: visible;
}
<div>
<svg width="100%" height="100%">
<rect fill="#ccc" x="100%" y="0" width="60px" height="100%"></rect>
<text x="100%" y="50%" stroke="black" text-anchor="start">Y-axis</text>
<rect x="0" y="0" width="100%" height="100%" fill="#c88"></rect>
</svg>
</div>
PS: Maybe you would prefer your text to have text-anchor="middle", and transform it in CSS with transform: translateX(30px) to place it in the centre of the "text" area — might look cleaner that way:
div {
padding-right: 60px;
}
svg {
overflow: visible;
}
text {
transform: translateX(30px);
}
<div>
<svg width="100%" height="100%">
<rect fill="#ccc" x="100%" y="0" width="60px" height="100%"></rect>
<text x="100%" y="50%" stroke="black" text-anchor="middle">Y-axis</text>
<rect x="0" y="0" width="100%" height="100%" fill="#c88"></rect>
</svg>
</div>

Reuse set of many objects but now assign each object a separate opacity, without copying all code?

Let's imagine we have a large set of many objects, say rectangles. They all have opacity 1.
Now imagine that we want to copy all of those objects again to create a new set, but this time each object would need to be assigned a separate opacity.
One can create many such sets, and each time all of the individual objects would separately be assigned a certain opacity.
In cross-browser compatible SVG1.1 (optionally with SMIL/CSS), is there a way to do this, without needing to redraw all of the shapes and their alignments all over again (redrawing would make the code sort of long), for example using set?
The pattern you are looking for goes like this:
<svg width="300" height="150"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="template" x="20" y="20" width="80" height="80" />
<use xlink:href="#template" x="100" style="opacity:0.6" fill="blue" />
<use xlink:href="#template" x="200" style="opacity:0.3" fill="green" />
</svg>
The <use> elements reuse the template element. The <rect> is now in the so-called "shadow DOM" below that use element. While it is treated as if it was a child, it cannot be targeted by CSS style rules. But it can inherit styles (or presentation attributes) from the parent <use> element.
Note that the template element does not set an opacity. As a default, it is rendered with opacity="1". Now if the <use> element sets another opacity, it can be applied to the cloned <rect> by inheritance.
If the template had an explicit opacity="1", the cloned <rect> would also get that. That style would have a higher specificity than the inherited one, and the rectangle would stay fully opaque.
Building on this answer, if you want to clone sets of elements at once but give each of them individual opacity values, CSS variables can be leveraged. Note that presentation attributes no longer work. The most concise way to write this is a stylesheet that turns out to be a list of the property values to use.
.stand {
--red: 1;
--amber: 0.3;
--green: 0.3;
}
.wait {
--red: 1;
--amber: 1;
--green: 0.3;
}
.go {
--red: 0.3;
--amber: 0.3;
--green: 1;
}
.stop {
--red: 0.3;
--amber: 1;
--green: 0.3;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="200">
<symbol id="trafficlight">
<rect x="20" y="20" width="60" height="160" />
<circle cx="50" cy="50" r="20" fill="#d00" style="opacity:var(--red, 1)" />
<circle cx="50" cy="100" r="20" fill="#fa0" style="opacity:var(--amber, 1)" />
<circle cx="50" cy="150" r="20" fill="#0b0" style="opacity:var(--green, 1)" />
</symbol>
<use x="0" xlink:href="#trafficlight" class="stand" />
<use x="100" xlink:href="#trafficlight" class="wait" />
<use x="200" xlink:href="#trafficlight" class="go" />
<use x="300" xlink:href="#trafficlight" class="stop" />
</svg>

SVG apply same transform-origin to all children of a group/symbol

I can't get reusable items or all children of a group to conform to a specified transform-origin. The goal is to be able to reuse the same shape over and over with the same template of style. However, considering transform-origin the styling, CSS or otherwise, does not cascade. It will only apply at time of <use>.
For example:
svg {
width: 125px; height: 125px;
background: rgba(0, 0, 0, 0.5);
}
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<defs>
<ellipse id="svg-ellipse-def" cx="500" cy="500" rx="140" ry="455" transform-origin="center" style="transform-origin: center"/>
</defs>
<symbol id="svg-ellipse" >
<ellipse cx="500" cy="500" rx="140" ry="455" transform-origin="center" style="transform-origin: center"/>
</symbol>
<g fill="none" stroke="red" stroke-width="50">
<use xlink:href="#svg-ellipse"/>
<use xlink:href="#svg-ellipse" transform="rotate(45)"/>
<use xlink:href="#svg-ellipse" transform="rotate(90)"/>
<use xlink:href="#svg-ellipse-def" transform="rotate(-45)"/>
</g>
</svg>
Essentially, the transform origin doesn't apply regardless if I use class= attribute or transform-origin= property or even inline style. I've also tried wrapping it in a <defs> container.
Desired outcome:
<use xlink:href="#svg-ellipse" transform="rotate(45)"/>
<use xlink:href="#svg-ellipse" transform="rotate(90)"/>
<use xlink:href="#svg-ellipse" transform="rotate(-45)"/>
But right now it looks like this:
<use xlink:href="#svg-ellipse" transform="rotate(45)" style="transform-origin:center"/>
<use xlink:href="#svg-ellipse" transform="rotate(90)" style="transform-origin:center"/>
<use xlink:href="#svg-ellipse" transform="rotate(-45)" style="transform-origin:center"/>
svg {
width: 125px; height: 125px;
background: rgba(0,0,0,0.5);
}
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<symbol id="svg-ellipse" >
<ellipse cx="500" cy="500" rx="140" ry="455"/>
</symbol>
<g fill="none" stroke="red" stroke-width="50">
<use xlink:href="#svg-ellipse"/>
<use xlink:href="#svg-ellipse" transform="rotate(45)" transform-origin="center"/>
<use xlink:href="#svg-ellipse" transform="rotate(90)" transform-origin="center"/>
<use xlink:href="#svg-ellipse" transform="rotate(-45)" transform-origin="center"/>
</g>
</svg>
According to the documentation:
If the ‘use’ element references a ‘symbol’ element:
In the generated content, the ‘use’ will be replaced by ‘g’, where all attributes from the ‘use’ element except for ‘x’, ‘y’, ‘width’, ‘height’ and ‘xlink:href’ are transferred to the generated ‘g’ element. An additional transformation translate(x,y) is appended to the end (i.e., right-side) of the ‘transform’ attribute on the generated ‘g’, where x and y represent the values of the ‘x’ and ‘y’ attributes on the ‘use’ element. The referenced ‘symbol’ and its contents are deep-cloned into the generated tree, with the exception that the ‘symbol’ is replaced by an ‘svg’.
Looking at the dev console, this is confirmed, and the style is applied inline but not honored:
Even if the <use> element has an inline styling of transform-origin, because the symbol now is converted to it's own SVG as a child of the <use> element, and it has it's own inline styling, shouldn't that take higher priority over it's parent's inline?
You can target the <use> element itself, but none of its content. The content can, in principle, inherit CSS properties. But the barrier you'll always run into is: neither the CSS transform nor the transform-origin property are inheritable.
If you rotate the <use> element, you rotate it around the tranform origin of the <use> element, while the contents of the shadow DOM stay in place relative to its root.
If you set a transform-origin for the <symbol> or <ellipse>, it will only be applied if you transform that itself, and the transformation will be cloned into each of its reuses.
The best solution I see is giving all use elements that reference the same symbol the same transform-origin. For the attribute selector to work, you'll need to leave off the xlink namespace. That is deprecated anyway, but you'll have to consider browser compatibility.
But then, the same is true for transform-origin support in SVG. That, by the way is the reason for
setting transform-box: fill-box. After there were some differences in implementation between Firefox and Chrome, it is now accepted that this
property is needed for SVG elements to transform them in relation to their bounding box. I've changed your example a bit to demonstrate.
svg {
width: 125px; height: 125px;
background: rgba(0, 0, 0, 0.5);
}
use[href="#symbol1"] {
transform-origin: center;
transform-box: fill-box;
}
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1500 1500">
<symbol id="symbol1" >
<ellipse cx="500" cy="500" rx="140" ry="455" />
</symbol>
<g fill="none" stroke="red" stroke-width="50">
<use href="#symbol1" transform="translate(200, 400)" />
<use href="#symbol1" transform="translate(200, 400) rotate(45)"/>
<use href="#symbol1" transform="translate(200, 400) rotate(90)"/>
<use href="#symbol1" transform="translate(200, 400) rotate(-45)"/>
</g>
</svg>

svg - keep fill texture original size when resizing a path

I define a svg <pattern> like this:
<svg height="10" width="10" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<pattern id="circles-1_4" patternUnits="userSpaceOnUse" width="10" height="10">
<image xlink:href="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxMHB4IiBoZWlnaHQ9IjEwcHgiIHZpZXdCb3g9IjAgMCAxMCAxMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTAgMTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxjaXJjbGUgY3g9IjEuMjUiIGN5PSIxLjI1IiByPSIxLjI1Ii8+PHJlY3QgZmlsbD0ibm9uZSIgd2lkdGg9IjEwIiBoZWlnaHQ9IjEwIi8+PC9zdmc+"
x="0" y="0" width="10" height="10">
</image>
</pattern>
</defs>
</svg>
visually, this is the equivalent of this:
So then I call my css for svg as a fill like this:
svg #VISUEL-3 * {fill: url(#circles-1);}
I get a pretty good result:
But when I display my graphic smaller (1/4 in this i.e), the fill adapt like this
It's difficult to see on the screenshots because the scale is broken due to the width 100% of stackoverflow but the vector-effect:non-scaling-stroke works perfectly so the strokes have the same size between the first and the second screenshot and the number "1,2,3,4,5,6" as well.
So as you can see the fill has adapted...
Is it possible to keep the same pattern size (same size of dots) like in css? That look messy visually when I have two graphics that are not of the same size and are next to each other.
Is my method right to obtain that? (I'm ready to change my method..)
The pattern elements are applied to the referencing element before transformations on the element or one of its parents are applied - so the pattern size gets transformed as well. The only way to counteract this is to write a seperate pattern element for each scale you us it at, including a patternTransform with the inverse scale. Fortunately, there is a mechanism for cloning patterns with a xlink:href attribute.
.simple {
fill: url(#dots);
}
.quarter {
fill: url(#quadrupleDots);
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="150">
<defs>
<pattern id="dots" patternUnits="userSpaceOnUse" width="10" height="10">
<circle r="1.25" cx="1.25" cy="1.25" />
</pattern>
<pattern id="quadrupleDots" xlink:href="#dots" patternTransform="scale(4)" />
</defs>
<rect id="shape" class="simple" x="20" y="20" width="100" height="100" />
<rect class="quarter" x="800" y="80" width="100" height="100" transform="scale(0.25)" />
</svg>

Animating Sketch' Generated SVG using CSS3

I have the following SVG code for an exported asset from a Sketch file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="116px" height="117px" viewBox="0 0 116 117" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="loader_circles">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<title>Group 2</title>
<desc>Created with Sketch.</desc>
<defs>
<circle id="path-1" cx="58.5" cy="58.5" r="58.5"></circle>
<mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="117" height="117" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<circle id="path-3" cx="59" cy="59" r="36"></circle>
<mask id="mask-4" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="72" height="72" fill="white">
<use xlink:href="#path-3"></use>
</mask>
</defs>
<g id="Common-elements" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-dasharray="78,34">
<g id="Group-2" stroke="#4A90E2" stroke-width="14">
<use id="Oval-8" mask="url(#mask-2)" xlink:href="#path-1"></use>
<use id="Oval-8" mask="url(#mask-4)" xlink:href="#path-3"></use>
</g>
</g>
</svg>
It is a loading spinner with two circles one inside of another, now my aim is to use CSS3 Keyframe animation to animate the two circles, mainly rotate it using transform property.
I am not an expert with SVG so I searched for ways to animate SVG with CSS and found that it is simply animating the elements inside of the SVG code for a particular path.
So I did this
#path-1 {
transform-origin: center;
animation: rotateClockwise 0.6s infinite linear;
}
#path-3 {
transform-origin: center;
animation: rotateAntiClockwise 0.6s infinite linear;
}
#keyframes rotateClockwise {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#keyframes rotateAntiClockwise {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}
The animation works, the two circles spins as it should but somehow the circles just gets malformed, the strokes of the circles just gets paler and thicker. The spinner looks like this when I don't do the transformation, I think the issue is mainly with the transform property
Here's a live demo:
http://jsbin.com/zipecefune
I am not sure why its happening, any ideas?
I'm not sure what is the source of the problem, but it seems wrong to animate something within defs as these are references, from MDN:
SVG allows graphical objects to be defined for later reuse. It is
recommended that, wherever possible, referenced elements be defined
inside of a <defs> element. Objects created inside a <defs> element
are not rendered immediately; instead, think of them as templates or
macros created for future use.
If instead of animating your circle elements you animate use, the problem is fixed (you need to rename the id property because they must be unique.
http://jsbin.com/qonokufimo/edit?html,css,js,output

Resources