如何动态设置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
相关产品推荐
相关产品推荐

