You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SVG描边动画在Safari浏览器中无法正常运行的问题求助

SVG描边动画在Safari中失效的解决方案

这问题我之前踩过坑!Safari对动态设置SVG描边样式后触发CSS动画的逻辑和Chrome差异很大,尤其是当SVG是动态加载的时候,固定延迟的setTimeout很容易导致样式设置时机不对,让动画直接跳过初始状态。给你几个亲测有效的解决方案:

方案1:用MutationObserver精准监听SVG加载完成(推荐)

固定延迟的setTimeout不可靠,Safari的SVG加载速度可能和Chrome不同,导致样式设置时SVG还没完全渲染,或者渲染后样式没被浏览器感知。改用MutationObserver可以精准捕捉SVG元素加载完成的时刻:

// 假设你的SVG容器有.character类
const svgContainer = document.querySelector('.character');
const observer = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
    // 检测到有节点被添加(SVG内容加载完成)
    if (mutation.addedNodes.length) {
      const $paths = svgContainer.getElementsByTagName('path');
      for (const path of $paths) {
        const totalLength = path.getTotalLength();
        path.style.strokeDashoffset = totalLength;
        path.style.strokeDasharray = totalLength;
        // 强制触发重绘,让Safari立即应用样式变化
        path.getBoundingClientRect();
      }
      observer.disconnect(); // 完成后停止监听,避免重复执行
    }
  });
});

// 开始监听容器的子节点变化
observer.observe(svgContainer, { childList: true, subtree: true });

方案2:保留setTimeout,但强制触发重绘

如果必须用固定延迟,在设置完stroke-dasharraystroke-dashoffset后,强制浏览器触发重绘,让Safari感知到初始样式:

setTimeout(() => { 
  const $paths = document.getElementsByTagName('path'); 
  for (const path of $paths) { 
    const totalLength = path.getTotalLength(); 
    path.style.strokeDashoffset = totalLength; 
    path.style.strokeDasharray = totalLength;
    // 读取offsetWidth强制重绘,void避免返回值干扰
    void path.offsetWidth;
  } 
}, 300);

方案3:用CSS变量传递路径长度

把初始描边样式移到CSS中,用CSS变量让JS传递路径长度,这样Safari能更稳定地识别动画初始状态:

修改CSS代码

.character path { 
  fill-opacity: 0; 
  stroke-opacity: 1; 
  stroke-width: 2px; 
  stroke: white;
  /* 用CSS变量定义初始描边参数 */
  stroke-dasharray: var(--path-length);
  stroke-dashoffset: var(--path-length);
  -webkit-animation: path 4s linear 1s both; 
  animation: path 4s linear 1s both; 
} 

@keyframes path { 
  70% { fill-opacity: 0; } 
  80% { stroke-dashoffset: 0; stroke-opacity: 1; } 
  100% { stroke-opacity: 0; stroke-dashoffset: 0; fill-opacity: 1; } 
}

修改JavaScript代码

setTimeout(() => { 
  const $paths = document.getElementsByTagName('path'); 
  for (const path of $paths) { 
    const totalLength = path.getTotalLength(); 
    // 设置CSS变量
    path.style.setProperty('--path-length', totalLength);
    // 强制重绘
    void path.offsetWidth;
  } 
}, 300);

额外注意点

  • 如果你的SVG是通过<img>标签加载的,不要用getElementsByTagName直接获取路径,需要先获取SVG的内部文档:
    const svgImg = document.querySelector('img.character');
    svgImg.onload = () => {
      const svgDoc = svgImg.contentDocument;
      const $paths = svgDoc.getElementsByTagName('path');
      // 后续样式设置逻辑...
    };
    
  • Safari对SVG动画的初始状态很敏感,必须确保动画开始前,stroke-dashoffset的初始值已经被浏览器完全应用,强制重绘是最常用的触发手段。

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

火山引擎 最新活动