I want animate the property stroke-dasharray of SVG circle with CSS var.
In green, the animations are correct and animate continuously and smoothly.
In red, the animation is incorrect because it animate in steps.
I think there is a problem with calculated CSS variable, but I don't understand what.
We can see that the animation with the square is correct even though it uses the calculated CSS var.
body {
display: flex;
}
svg {
width: 200px;
height: 200px;
}
circle.good {
stroke: green;
stroke-width: 5;
animation: good-dash 2s ease-in-out infinite;
}
circle.bad {
stroke: red;
stroke-width: 5;
animation: bad-dash 2s ease-in-out infinite;
--stroke-dasharray: 10;
}
.square {
width: 200px;
height: 200px;
background-color: green;
animation: good-roll 2s infinite ease-in-out both;
position: relative;
--left: 1;
}
@keyframes good-dash {
0% {
stroke-dasharray: 1, 10;
}
50% {
stroke-dasharray: 1, 5;
}
100% {
stroke-dasharray: 1, 10;
}
}
@keyframes bad-dash {
0% {
stroke-dasharray: 1, var(--stroke-dasharray);
}
50% {
stroke-dasharray: 1, calc(var(--stroke-dasharray) / 2);
}
100% {
stroke-dasharray: 1, var(--stroke-dasharray);
}
}
@keyframes good-roll {
0% {
left: calc(var(--left) * 1px);
}
50% {
left: calc(var(--left) * 50px);
}
100% {
left: calc(var(--left) * 1px);
}
}
<svg viewBox="25 25 50 50">
<circle class="good" cx="50" cy="50" r="20" fill="none"/>
</svg>
<svg viewBox="25 25 50 50">
<circle class="bad" cx="50" cy="50" r="20" fill="none"/>
</svg>
<div class="square"></div>
Units are mandatory in calc expressions that involve things that are not naturally unitless and really you should try to use them everywhere as CSS mostly demands them.
opacity is a genuinely unitless property, it's just a <number>
in the specification.
stroke-dasharray however is not unitless its either a <length>
or a <percentage>
SVG has a special 'legacy' rule that says that some properties unique to SVG that would normally require units can be written without units.
When it comes to calc expressions though that specific SVG rule allowing the omission of units does not apply and everything that should have a unit, must have a unit. Chrome has not currently implemented this requirement but I expect they will at some point.
body {
display: flex;
}
svg {
width: 200px;
height: 200px;
}
circle.good {
stroke: green;
stroke-width: 5;
animation: good-dash 2s ease-in-out infinite;
}
circle.bad {
stroke: red;
stroke-width: 5;
animation: bad-dash 2s ease-in-out infinite;
--stroke-dasharray: 10px;
}
.square {
width: 200px;
height: 200px;
background-color: green;
animation: good-roll 2s infinite ease-in-out both;
position: relative;
--left: 1;
}
@keyframes good-dash {
0% {
stroke-dasharray: 1, 10;
}
50% {
stroke-dasharray: 1, 5;
}
100% {
stroke-dasharray: 1, 10;
}
}
@keyframes bad-dash {
0% {
stroke-dasharray: 1px, var(--stroke-dasharray);
}
50% {
stroke-dasharray: 1px, calc(var(--stroke-dasharray) / 2);
}
100% {
stroke-dasharray: 1px, var(--stroke-dasharray);
}
}
@keyframes good-roll {
0% {
left: calc(var(--left) * 1px);
}
50% {
left: calc(var(--left) * 50px);
}
100% {
left: calc(var(--left) * 1px);
}
}
<svg viewBox="25 25 50 50">
<circle class="good" cx="50" cy="50" r="20" fill="none"/>
</svg>
<svg viewBox="25 25 50 50">
<circle class="bad" cx="50" cy="50" r="20" fill="none"/>
</svg>
<div class="square"></div>