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

环形进度条动画在谷歌Chrome失效,其他浏览器正常运行

环形进度条Chrome浏览器失效问题解决建议

问题描述

开发了一个进入视口时触发的环形进度条动画,该效果在除Google Chrome外的所有浏览器中都能正常工作,但在Chrome中无法运行,怀疑问题与JavaScript代码相关,寻求解决建议。

问题分析

从提供的代码来看,Chrome失效的核心原因集中在以下几点:

  • CSS中渐变ID与HTML不匹配,导致渐变样式无法加载
  • 针对webkit的专属媒体查询覆盖了标准过渡属性,干扰动画执行逻辑
  • IntersectionObserver的阈值设置过高,可能导致元素进入视口时无法及时触发
  • Chrome对SVG属性过渡的缓存机制影响了重置状态后的二次触发

解决步骤

  1. 修复渐变ID引用错误
    CSS中.circle-progress-value的stroke属性使用了url(#circle-gradient-%id%),但HTML中渐变ID为circle-gradient,删除%id%占位符,保证样式引用正确。

  2. 移除webkit专属媒体查询块
    现代Chrome已完全支持标准CSS过渡属性,该媒体查询块会覆盖标准过渡规则,直接删除即可恢复正常过渡逻辑。

  3. 降低IntersectionObserver触发阈值
    将阈值从0.5调整为0.1,确保元素刚进入视口边缘时就能触发动画,避免因元素尺寸或布局问题导致触发延迟。

  4. 优化动画重置逻辑
    当元素离开视口重置状态时,先临时移除过渡属性,设置初始值后再重新添加过渡,规避Chrome的过渡缓存影响下次触发。

修正后的完整代码

JavaScript

document.addEventListener('DOMContentLoaded', () => {
  const circleProgressBar = document.querySelector('.circle-progress-value');
  const circleProgressNumber = document.querySelector('.circle-progress-number');
  const checkmarkContainer = document.querySelector('.checkmark-container');

  const countUp = (start, end, element, duration) => {
    let current = start;
    const stepTime = Math.abs(Math.floor(duration / (end - start)));
    const timer = setInterval(() => {
      if (current <= end) {
        element.textContent = current++;
      } else {
        clearInterval(timer);
      }
    }, stepTime);
  };

  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        circleProgressBar.style.transition = 'stroke-dashoffset 2000ms';
        circleProgressBar.style.strokeDashoffset = '0';
        countUp(0, 50, circleProgressNumber, 2000);
        setTimeout(() => {
          checkmarkContainer.style.opacity = '1';
        }, 2000);
      } else {
        // 重置时先移除过渡,避免缓存干扰
        circleProgressBar.style.transition = 'none';
        circleProgressBar.style.strokeDashoffset = '283';
        circleProgressNumber.textContent = '0';
        checkmarkContainer.style.opacity = '0';
        // 延迟恢复过渡,确保下次触发正常
        setTimeout(() => {
          circleProgressBar.style.transition = 'stroke-dashoffset 2000ms';
        }, 10);
      }
    });
  }, {
    threshold: 0.1
  });

  observer.observe(circleProgressBar);
});

CSS

.circle-progress-container {
  position: relative;
  display: inline-block;
  width: 100%;
  padding-bottom: 100%;
  overflow: visible;
}

.bar-container {
  width: 400px;
}

.circle-progress {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.circle-progress-bg,
.circle-progress-value {
  stroke-linecap: round;
}

.circle-progress-bg {
  stroke: lightgray;
}

.circle-progress-value {
  stroke: url(#circle-gradient);
  stroke-dasharray: 283;
  stroke-dashoffset: 283;
  transition: stroke-dashoffset 2s;
  transition-property: stroke-dashoffset;
}

.circle-progress-text {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: bold;
  text-align: center;
}

.circle-progress-number-container {
  display: flex;
  align-items: baseline;
}

.circle-progress-number {
  transition: 2s;
}

.circle-progress-label {
  font-size: 12px;
  font-weight: normal;
  margin-top: -10px;
}

.checkmark-container {
  position: absolute;
  top: -2px;
  left: 50%;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 0.5s, transform 0.5s;
}

.checkmark-circle {
  position: relative;
  width: calc(16px + 5px);
  height: calc(16px + 5px);
  background-color: white;
  border-radius: 50%;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}

.checkmark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  stroke: deepskyblue;
  stroke-linecap: round;
}

HTML

<div class="bar-container">
  <div class="circle-progress-container">
    <svg class="circle-progress" viewBox="0 0 100 100">
      <defs>
        <linearGradient id="circle-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
          <stop offset="0%" style="stop-color:red"/>
          <stop offset="100%" style="stop-color:blue"/>
        </linearGradient>
      </defs>
      <circle class="circle-progress-bg" cx="50" cy="50" r="45" stroke-width="1" fill="none" />
      <circle class="circle-progress-value" cx="50" cy="50" r="45" stroke-width="1" fill="none" />
    </svg>
    <div class="circle-progress-text">
      <div class="circle-progress-number-container" style="font-size: 40px;">
        <span class="circle-progress-number">50</span><span>+</span>
      </div>
      <div class="circle-progress-label" style="font-size: 14px;">Projects</div>
    </div>
    <div class="checkmark-container">
      <div class="checkmark-circle">
        <svg class="checkmark" width="16px" height="16px" viewBox="0 0 20 20">
          <polyline points="6,10 9,13 14,8" stroke-width="2" fill="none" />
        </svg>
      </div>
    </div>
  </div>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:58:10