SVG动画:Chrome性能差/迟缓

8
我们正在开发一个相当复杂的场景,其中有很多移动部件,直到现在都没有涉及任何SVG动画。
一切都很顺利,性能良好,直到我们引入了一个带有几条虚线的SVG,并使用stroke-dashoffset属性进行了动画处理。
在Edge或Firefox中没有任何区别,但在Chrome中,整个场景的动画变得卡顿和缓慢。
我们甚至尝试了两种方法来达到同样的目的 - CSS关键帧和SVG元素内的SMIL - 但两者的性能都同样差。
我们是否遗漏了Chrome的性能技巧?
编辑:示例
标记:

.stream {
  animation: stream 10s infinite;
}

@keyframes stream {
  100% {
    stroke-dashoffset: 100;
  }
}
<svg version="1.0" id="streams" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 225.32 66.19" enable-background="new 0 0 225.32 66.19" xml:space="preserve">
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M107.38,50.54c0,0-6.78-84.52-106.51-22.2" />
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M110.49,45.31c-0.63-13.01-4.56-44.87-27.83-43.8c-27.6,1.27-37.33,39.66-38.49,60.34"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M180.63,59.88c-0.69-9.65-3.6-30.18-15.76-45.51C148.44-6.34,131.85,2.22,128.87,5c-2.89,2.7-12.81,7.14-14.28,42"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M118.59,45.41c2.4-10.18,9.9-31.97,30.87-37.59c26.03-6.98,55.13,9.32,72.02,19.37"/>
</svg>


有一个可以复现的例子吗? - Chris W.
我们在任何JS动画中都使用requestAnimationFrame。SVG动画使用SMIL或CSS(两者都很缓慢),因此不适用于那里。 - Geat
无论如何,您都可以将CSS重构为JS动画,以便从性能优化中受益。在没有展示示例的情况下,使用CSS可做的事情不多,尤其是针对性能优化方面。 - Joe Warner
你主要使用过渡还是变换? - Joe Warner
我会在帖子中添加一个例子。 - Geat
显示剩余2条评论
3个回答

3

如何在SVG路径上无限制地移动标记,而不会导致CPU使用率过高? 的副本。

真正的问题在于SVG实现不佳,参见Chrome bug

一种解决方法是使用JavaScript动画降低帧率,可以参考代码示例。

这种特殊情况可以使用虚线圆和CSS transform: rotate3d() 实现。但是在今天的SVG实现中,“GPU transforms” translate/rotate 的性能也很差。解决方法:将SVG代码包装在 <div> 中并对其进行动画处理,就可以将CPU使用率降至零。相关内容请参见crmarsh.com/svg-performance

const svg_elem = document.getElementById('streams')

const animateDashTime = 200 // milliseconds
let anim_dash_offset = 0
let animateDashTimer = null

function animateDashStep(){

  anim_dash_offset += 1

  svg_elem.setAttribute('style',
    '--stroke-dashoffset: '+anim_dash_offset);

  // repeat
  animateDashTimer = setTimeout(
    animateDashStep,
    animateDashTime
  )
}

// start
animateDashStep()

// stop
//clearTimeout(animateDashTimer)
<svg version="1.0" id="streams" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 225.32 66.19" enable-background="new 0 0 225.32 66.19" xml:space="preserve" 

  style="--stroke-dashoffset: 0"
>
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" 
  
    stroke-dasharray="3,4" 
    stroke-dashoffset="var(--stroke-dashoffset)" 

    d="M107.38,50.54c0,0-6.78-84.52-106.51-22.2"
  />
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" stroke-dashoffset="var(--stroke-dashoffset)" d="M110.49,45.31c-0.63-13.01-4.56-44.87-27.83-43.8c-27.6,1.27-37.33,39.66-38.49,60.34"
  />
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" stroke-dashoffset="var(--stroke-dashoffset)" d="M180.63,59.88c-0.69-9.65-3.6-30.18-15.76-45.51C148.44-6.34,131.85,2.22,128.87,5c-2.89,2.7-12.81,7.14-14.28,42"/>
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" stroke-dashoffset="var(--stroke-dashoffset)" d="M118.59,45.41c2.4-10.18,9.9-31.97,30.87-37.59c26.03-6.98,55.13,9.32,72.02,19.37"/>
</svg>


1

您需要将动画的缓动设置为linear。运行下面的代码片段,以查看它在没有这个粗重的减速情况下运行。

.stream {
  animation: stream 10s linear infinite;
}

@keyframes stream {
  100% {
    stroke-dashoffset: 100;
  }
}
<svg version="1.0" id="streams" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 225.32 66.19" enable-background="new 0 0 225.32 66.19" xml:space="preserve">
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M107.38,50.54c0,0-6.78-84.52-106.51-22.2" />
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M110.49,45.31c-0.63-13.01-4.56-44.87-27.83-43.8c-27.6,1.27-37.33,39.66-38.49,60.34"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M180.63,59.88c-0.69-9.65-3.6-30.18-15.76-45.51C148.44-6.34,131.85,2.22,128.87,5c-2.89,2.7-12.81,7.14-14.28,42"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M118.59,45.41c2.4-10.18,9.9-31.97,30.87-37.59c26.03-6.98,55.13,9.32,72.02,19.37"/>
</svg>


那并没有解决迟缓的问题(我做了另一个更改,虽然我不确定是什么!),但它确实使动画变得更好,所以感谢您的提示! - Geat
@Geat,你最终找到了是哪个更改解决了延迟问题吗?你还记得那是什么吗?我在使用动画的stroke-dashoffset时也遇到了同样的问题... - Souleste

0

你可以使用animation-timing-function: steps(n),而不是Mila Nautikus提供的JavaScript方法,以实现相同的效果。设置nm *(动画循环期间更改的stroke-dashoffset数量),可以获得更平滑的动画效果,例如:

.stream {
  animation: stream 0.5s steps(14) infinite;
}

@keyframes stream {
  100% {
    stroke-dashoffset: 7;
  }
}
<svg version="1.0" id="streams" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 225.32 66.19" enable-background="new 0 0 225.32 66.19" xml:space="preserve">
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M107.38,50.54c0,0-6.78-84.52-106.51-22.2" />
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M110.49,45.31c-0.63-13.01-4.56-44.87-27.83-43.8c-27.6,1.27-37.33,39.66-38.49,60.34"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M180.63,59.88c-0.69-9.65-3.6-30.18-15.76-45.51C148.44-6.34,131.85,2.22,128.87,5c-2.89,2.7-12.81,7.14-14.28,42"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M118.59,45.41c2.4-10.18,9.9-31.97,30.87-37.59c26.03-6.98,55.13,9.32,72.02,19.37"/>
</svg>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接