【问题标题】:Animation not working with calculated CSS variables动画不适用于计算的 CSS 变量
【发布时间】:2021-05-08 15:06:00
【问题描述】:

我想用 CSS var 为 SVG 圆的属性 stroke-dasharray 设置动画。

绿色表示动画正确且动画连续流畅。
红色表示动画不正确,因为它分步进行。

我认为计算的 CSS 变量有问题,但我不明白是什么。
我们可以看到带有正方形的动画是正确的,即使它使用了计算出的 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>

【问题讨论】:

  • 在什么浏览器中?
  • @TemaniAfif 问题中写的内容不应该在任何浏览器中工作。它可能在 Chrome 中执行,因为它似乎有一个非标准的 calc 实现。 Safari、Firefox 和 w3c 更严格。

标签: css svg css-animations svg-animate css-variables


【解决方案1】:

单位在 calc 表达式中是强制性的,涉及的东西并非自然无单位,实际上您应该尝试在任何地方使用它们,因为 CSS 大多需要它们。

  • opacity 是一个真正的无单位属性,它只是一个 &lt;number&gt; in the specification。

  • stroke-dasharray 但不是无单位的,它要么是 &lt;length&gt; 要么是 &lt;percentage&gt;

  • SVG 有一个特殊的“遗留”规则,即 SVG 特有的一些通常需要单位的属性可以在没有单位的情况下编写。

当涉及到计算表达式时,尽管允许省略单位的特定 SVG 规则不适用,everything that should have a unit, must have a unit。 Chrome 目前还没有实现这个要求,但我希望他们会在某个时候实现。

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>

【讨论】:

  • 我不认为它们是强制性的,我们可以使用 calc() 没有单位
  • 可能适用于某些特定情况,但我仍然不同意通常我们需要在 calc() 中使用单位。这取决于属性可以接受的价值。这例如是有效的:jsfiddle.net/umkhgyar/1
  • 另一个应该可以正常工作的不透明度示例:jsfiddle.net/umkhgyar/2
  • 确实,使用px单位解决问题。但是在文档中我们看不到与任何单元一起使用的 stroke-dasharray:developer.mozilla.org/en-US/docs/Web/SVG/Attribute/…。该属性接受无单位值,因此我认为它应该在动画中没有单位的情况下工作。
  • 值得了解作为最佳实践应该做的事情与仅在一两个浏览器中在有限的测试用例中起作用之间的区别。罗伯特给出了很好的建议,如果您想避免将来出现问题,请听听专家的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 2017-03-14
  • 1970-01-01
  • 2014-11-11
  • 2018-02-13
  • 2016-10-10
  • 2017-06-25
相关资源
最近更新 更多