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

如何动态设置keyframes的stroke-dashoffset实现环形百分比进度条

动态环形百分比进度条实现方案

原有代码问题

  • 错误尝试获取不存在的keyframes元素,JS没有直接操作@keyframes规则的简单原生API,不需要走这个实现路径
  • 存在基础语法错误:变量声明用了不存在的val关键字、setStroke-offset是不存在的原生方法、clearInterval调用时没有传入要清除的定时器ID
  • 数字计数间隔固定为20ms,当目标进度不是100时,数字跳动和环形动画进度不同步

实现步骤

1. 修改CSS,通过CSS变量传递动态值

不需要硬编码动画终点的stroke-dashoffset,用CSS自定义属性接收JS传入的动态目标值即可,修改后的CSS代码如下:

.OuterCircle {
  width: 120px;
  height:120px;
  border-radius:50%;
  padding: 20px;
  box-shadow: 6px 6px 10px -1px rgba(0,0,0,0.15),
             -6px -6px 10px -1px rgba(255,255,255,0.7);
}

.InnerCircle {
  width: 120px;
  height: 120px;
  border-radius:50%;
  display: flex;
  justify-content: center;
  align-items: center;
  box-shadow: inset 4px 4px 6px -1px rgba(0,0,0,0.2),
                 -4px -4px 6px -1px rgba(255,255,255,0.7),
                 -0.5px -0.5px 0px rgba(255,255,255,1),
                 0.5px 0.5px 0px rgba(0,0,0,0.15),
                 0px 12px 10px -10px rgba(0,0,0,0.05);
}

circle{
  fill:none;
  stroke: url(#GradientColor);
  stroke-width: 20px;
  /* 圆周长数值,和你原来写的472保持一致即可,不需要修改 */
  --circle-length: 472;
  stroke-dasharray: var(--circle-length);
  /* 初始状态偏移量等于周长,进度为0 */
  stroke-dashoffset: var(--circle-length);
  animation: anim 2s linear forwards;
}

@keyframes anim{
  100%{
      stroke-dashoffset: var(--target-offset);
  }
}

2. HTML结构保持不变

你原来写的HTML结构不需要做任何调整,直接沿用即可:

<div class="percentBox">
  <div class="OuterCircle">
    <div class="InnerCircle">
      <div id="number"></div>
    </div>
  </div>
  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="160px" height="160px">
    <defs>
      <linearGradient id="GradientColor">
        <stop offset="0%" stop-color="#e91e63" />
        <stop offset="100%" stop-color="#673ab7" />
      </linearGradient>
    </defs>
    <circle cx="80" cy="80" r="70" stroke-linecap="round" />
  </svg>
</div>

3. 替换JS逻辑

核心是通过计算得到目标偏移量,传给CSS变量,同时同步数字计数动画,代码如下:

// 这里替换成你需要动态设置的百分比值,支持0-100任意数字
const TARGET_PERCENT = 65;
const numberEl = document.getElementById("number");
const circleEl = document.querySelector("circle");
// 和CSS中--circle-length的数值保持一致
const CIRCLE_LENGTH = 472;
let counter = 0;

// 核心公式:目标偏移量 = 圆周长 * (1 - 进度值/100)
const targetOffset = CIRCLE_LENGTH * (1 - TARGET_PERCENT / 100);
// 将计算好的目标值传给CSS变量,动画会自动读取这个值作为终点
circleEl.style.setProperty("--target-offset", targetOffset);

// 自动计算计数间隔,保证数字跳动和环形动画2s的时长完全同步
const countInterval = 2000 / TARGET_PERCENT;
const timer = setInterval(() => {
  if(counter >= TARGET_PERCENT){
    clearInterval(timer);
    numberEl.innerHTML = `${TARGET_PERCENT}%`;
    return;
  }
  counter += 1;
  numberEl.innerHTML = `${counter}%`;
}, countInterval)

逻辑说明

  • 进度条的核心计算逻辑和你硬编码时完全一致:进度100%时stroke-dashoffset为0,圆环完全显示;进度0%时偏移量等于周长,圆环完全隐藏。
  • 不需要复杂的关键帧操作,CSS变量传值的方案兼容性好,所有现代浏览器都支持,代码维护成本更低。
  • 数字计数的间隔根据目标进度动态计算,不管传入的进度值是多少,都能和环形动画保持完全同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:48:24