You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firefox中SVG的CSS transform失效问题求助

解决SVG沙漏动画在Firefox不工作的问题

我帮你排查了这个问题——Chrome能正常运行但Firefox里#upper-fill-clip和#lower-fill-clip的平移动画没效果,核心原因是Firefox对被clip-path包裹的SVG元素应用CSS transform的处理逻辑和Chrome不一致,CSS变换的上下文计算在这里出现了兼容性问题。

下面给你两种可行的解决方案,优先推荐第一种,兼容性更稳定:

方案一:改用SVG原生动画(推荐)

SVG自带的<animateTransform>元素是专为SVG元素设计的动画方式,所有主流浏览器都能完美支持,不会有CSS变换的上下文冲突。

修改步骤:

  1. 先调整CSS,保留沙漏翻转的CSS动画(这个Firefox支持正常),移除原来的flowdown、fillup动画及对应元素样式:
@keyframes flip { 
  0% { transform: rotate(0deg); } 
  99.4% { transform: rotate(0deg); } 
  100% { transform: rotate(180deg); } 
}
#hourglass { 
  fill: #000000; 
  animation-duration: 30s; 
  animation-timing-function: linear; 
  animation-iteration-count: infinite; 
  animation-name: flip; 
  transform-origin: center center; 
}
  1. 在SVG的两个矩形元素内添加<animateTransform>动画:
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="212.17653" height="310" id="hourglass">
  <defs>
    <clipPath id="flowdown">
      <path d="m 153.09976,190.92975 c 22.09717,217.28036 179.31249,274.21877 197.89215,327.9765 l 62.9374,0 c 18.72854,-53.17156 176.30873,-105.92478 197.9976,-327.99097" style="stroke-width:0" />
    </clipPath>
    <clipPath id="fillup">
      <path d="M 296.23029,608.69417 C 236.36177,663.1914 150.52311,748.96721 150.52311,928.875 l 231.9375,0 231.9375,0 c 0,-181.67405 -83.81727,-266.73823 -143.5691,-320.06035" style="stroke-width:0" />
    </clipPath>
  </defs>
  <g transform="matrix(0.3117516,0,0,0.3117516,-13.144444,-11.10242)" id="layer1">
    <g transform="translate(14,-26)" id="g4027">
      <rect width="648.51801" height="43.605999" x="44.201607" y="-1039.9561" transform="scale(1,-1)" id="rect3782" style="fill:#000000;fill-opacity:1;stroke:none" />
      <rect width="579.82764" height="60" x="78.546791" y="-999.65149" transform="scale(1,-1)" id="rect3784" style="fill:#000000;fill-opacity:1;stroke:none" />
    </g>
    <path d="m 150.53125,138.59375 c 0,276.24024 202.375,328.98438 202.375,390.46875 0,1.83297 -1.12281,3.21907 -0.71875,4.6875 -0.40197,1.4611 0.71875,2.83465 0.71875,4.65625 0,59.91583 -202.375,114.22851 -202.375,390.46875 l 231.9375,0 231.9375,0 c 0,-282.29589 -202.375,-331.32933 -202.375,-390.46875 0,-1.8216 1.12072,-3.19515 0.71875,-4.65625 0.40406,-1.46843 -0.71875,-2.85453 -0.71875,-4.6875 0,-61.32924 202.375,-108.17286 202.375,-390.46875 l -231.9375,0 z" id="path3788" style="fill:none;stroke:#000000;stroke-width:30;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
    <g transform="translate(14,-26)" id="g4043">
      <rect width="648.51801" height="43.605999" x="44.201607" y="77.651443" id="rect4033" style="fill:#000000;fill-opacity:1;stroke:none" />
      <rect width="579.82764" height="60" x="78.546791" y="117.95601" id="rect4035" style="fill:#000000;fill-opacity:1;stroke:none" />
    </g>
    <g clip-path="url(#flowdown)">
      <rect width="744.09448" height="1052.3622" x="0" y="0" id="upper-fill-clip">
        <!-- 上层沙子下落动画 -->
        <animateTransform
          attributeName="transform"
          type="translate"
          from="0, 18%"
          to="0, 49.2%"
          dur="30s"
          repeatCount="indefinite"
          additive="replace"
          calcMode="linear"
        />
      </rect>
    </g>
    <g clip-path="url(#fillup)" >
      <rect width="744.09448" height="1052.3622" x="0" y="0" id="lower-fill-clip">
        <!-- 下层沙子填满动画 -->
        <animateTransform
          attributeName="transform"
          type="translate"
          from="0, 86.7%"
          to="0, 57.7%"
          dur="30s"
          repeatCount="indefinite"
          additive="replace"
          calcMode="linear"
        />
      </rect>
    </g>
  </g>
</svg>

方案二:给矩形套外层容器,转移CSS动画

如果更倾向于用CSS动画,可以给被裁剪的矩形外面加一层<g>容器,把CSS变换动画应用到这个外层容器上,这样Firefox能正确识别变换上下文:

修改步骤:

  1. 保留原来的CSS代码,调整选择器指向外层容器:
@keyframes flowdown { 0% { transform: translateY(18%); } 100% { transform: translateY(49.2%); } }
@keyframes fillup { 0% { transform: translateY(86.7%); } 100% { transform: translateY(57.7%); } }
@keyframes flip { 0% { transform: rotate(0deg); } 99.4% { transform: rotate(0deg); } 100% { transform: rotate(180deg); } }
#hourglass, #upper-fill-container, #lower-fill-container { fill: #000000; animation-duration: 30s; animation-timing-function: linear; animation-iteration-count: infinite; }
#hourglass { animation-name: flip; transform-origin: center center; }
#upper-fill-container { animation-name: flowdown; transform: translateY(18%); }
#lower-fill-container { animation-name: fillup; transform: translateY(86.7%); }
  1. 修改SVG中的裁剪容器部分:
<g clip-path="url(#flowdown)">
  <g id="upper-fill-container">
    <rect width="744.09448" height="1052.3622" x="0" y="0" id="upper-fill-clip" />
  </g>
</g>
<g clip-path="url(#fillup)" >
  <g id="lower-fill-container">
    <rect width="744.09448" height="1052.3622" x="0" y="0" id="lower-fill-clip" />
  </g>
</g>

原理说明

Firefox对SVG元素的CSS transform支持有特殊限制:当元素直接被clip-path裁剪时,CSS变换的坐标系计算会和Chrome产生差异,导致变换不生效。而SVG原生动画直接操作元素的SVG属性,不会有这个问题;给元素套外层容器则是把变换上下文转移到了未被裁剪的<g>元素上,Firefox就能正确解析CSS变换了。

内容的提问来源于stack exchange,提问作者besrabasant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:23:33