如何在 Firefox 中将 CSS 动画应用于 SVG 遮罩?

How to apply CSS animation to a SVG mask in Firefox?

我正在尝试将 css 动画应用于 svg 蒙版。虽然它在 Chrome (v. 73) 上运行良好,但我无法在 Firefox (v. 66) 上运行。

我不明白为什么我当前的示例(见下文)无法在 Firefox 上运行

注意:根据 Can I use,Firefox 66 不需要任何前缀即可使 transform 正常工作。我打算添加它们以支持旧版本,但这无法解决我当前的问题。

这是我的问题的一个小例子:(HTML 在我的解释中添加了 id 用于命名对象)

.canvas {
  border: solid 1px lime;
  background: lightblue;
}

.animated {
  transform-origin: center center;
  animation: myAnimation 1s ease forwards;
}

@keyframes myAnimation {
  0% {
    transform: scale(0);
  }
  100% {
    transform: scale(0.8);
  }
}
<html>

<head>
  <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
  <center>
    <div>
      <svg class="canvas" viewBox="0 0 100 100" width="150px" height="150px">

          <defs>
            <mask id="gmask" fill="white">
              <!-- Mask is defined here as a black circle in a white background -->
              <rect x="0" y="0" width="100" height="100" fill="white" />
              <circle id="maskCircle" class="animated" cx="50" cy="50" r="25" fill="black" />
            </mask>
          </defs>

          <!-- Pink circle is animated in both browsers -->
          <circle id="testCircle" class="animated" cx="50" cy="50" r="50" fill="pink" />

          <circle id="outerCircle" class="outer" cx="50" cy="50" r="25" mask="url(#gmask)" />
        </svg>
    </div>
  </center>
</body>

</html>

我正在尝试 transform: scale 大小为 25 的圆圈 maskCircle00.8 这样当它作为蒙版应用到outerCircle(也是 25 码)。

在 Chrome 上,我可以获得预期的输出 view in Chrome ; while in Firefox the animation is not applied, so the mask circle remain it's full size (25) and totally hide outerCircle view in Firefox。

(好吧,几乎完全隐藏它,因为我可以看到圆圈应该有的一条细线,但即使没有动画它也会显示,所以我相信这是 mask/circle 未以完全相同的尺寸呈现并且与我的问题无关)。

作为测试,我将相同的动画应用到一个简单的 svg 对象(testCircle,粉红色圆圈)并且效果很好。这让我觉得这个问题与口罩有关。

我想动画蒙版很常见并且应该是可能的,所以我猜我做错了什么 chrome 可以但不是 Firefox。

知道如何让它同时适用于两者吗?

这是使用 SMIL 完成的方法:

.center{margin:0 auto;width:150px;}

.canvas {
  border: solid 1px lime;
  background: lightblue;
}
<div class="center">
    <div>
      <svg class="canvas" viewBox="-50 -50 100 100" width="150px" height="150px">

          <defs>
            <mask id="gmask" fill="white">
              <!-- Mask is defined here as a black circle in a white background -->
              <rect x="-50" y="-50" width="100" height="100" fill="white" />
              <circle id="maskCircle" class="animated"  r="25" fill="black" >
                <animateTransform 
                  attributeType="XML" 
                   attributeName="transform" 
                   type="scale"
                   values="0;.8"
                   calcMode="spline"
                   keySplines="0.4 0 0.2 1"
                   dur="1s" 
                   fill="freeze"
                    /> 
              </circle>
            </mask>
          </defs>

          <!-- Pink circle is animated in both browsers -->
        <circle id="testCircle" class="animated"  r="50" fill="pink">
          <animateTransform 
                  attributeType="XML" 
                   attributeName="transform" 
                   type="scale"
                   values="0;.8"
                   calcMode="spline"
                   keySplines="0.4 0 0.2 1"
                   dur="1s" 
                   fill="freeze"
                    /> 
        </circle>

          <circle id="outerCircle" class="outer"  r="25" mask="url(#gmask)" />
        </svg>
    </div>
  </div>

我正在使用 calcMode="spline" keySplines="0.4 0 0.2 1" 而不是缓动。

看到这个:SVG SMIL animateTransform easing

我正在使用 fill="freeze" 而不是 CSS forwards。希望对你有帮助。

正如罗伯特所说,最好使用适用于所有现代浏览器的 SVG 遮罩。

我没有使用scale()动画,而是使用了圆的半径动画。这更容易,因为您不必担心在缩放后定位圆圈。

你有一个复杂的动画形式,所以在黑环之前的第一阶段我应用了遮罩动画组合。

<mask id="gmask" fill="white">
 <circle id="maskCircle" class="animated" cx="50" cy="50" r="0" fill="black" >
  <animate id="an1" attributeName="r"  dur="0.8s" values="0;20" fill="freeze" />
 </circle>
</mask>

和圆半径外的环动画

<circle id="testCircle"  cx="50" cy="50" r="25" fill="pink"  >
      <animate attributeName="r" begin="an1.end" dur="0.2s" from="25" to="40" 
         fill="freeze"/>
</circle>   

下面是完成的代码。

.canvas {
  border: solid 1px lime;
  background: lightblue;
<html>

<head>
  <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
  <center>
    <div>
      <svg class="canvas" viewBox="0 0 100 100" width="150px" height="150px">

          <defs>
            <mask id="gmask" fill="white">
              <!-- Mask is defined here as a black circle in a white background -->
              <rect x="0" y="0" width="100" height="100" fill="white" /> 
              <circle id="maskCircle" class="animated" cx="50" cy="50" r="0" fill="black" >
       <animate id="an1" attributeName="r"  dur="0.8s" values="0;20" fill="freeze" />
     </circle> 
            </mask>
          </defs>

          <!-- Pink circle is animated in both browsers --> 
    <circle id="testCircle"  cx="50" cy="50" r="25" fill="pink"  >
            <animate attributeName="r" begin="an1.end" dur="0.2s" from="25" to="40" fill="freeze"/>
   </circle>    
    <circle id="outerCircle" class="outer" cx="50" cy="50" r="25"  mask="url(#gmask)"/>
          

          
        </svg>
    </div>
  </center>
</body>

</html>