环形进度条需用js同步--progress自定义属性,css通过calc()将其转为stroke-dashoffset;避免transition跳变应使用@keyframes单向动画;ie不支持calc(var())须降级为js直接设置;动态更新需requestanimationframe节流并阈值过滤。

用 --progress 自定义属性控制环形进度值
环形进度条本质是 SVG 的 <circle></circle> 或 <path></path> 的 stroke-dashoffset 和 stroke-dasharray 配合动画。CSS 自定义属性不能直接驱动 SVG 属性,但可以作为中间变量被 calc() 或 CSS-in-JS 读取——最稳妥的做法是用 JS 同步更新 style.setProperty('--progress', value),再让 CSS 通过 calc() 把它转为偏移量。
关键点:环形周长固定(比如 251.2 对应 r=40),进度百分比 0–100 映射为 dash-offset = 周长 × (1 − 进度/100)。所以 CSS 中需写成:
svg circle {
stroke-dasharray: 251.2;
stroke-dashoffset: calc(251.2 - (251.2 * var(--progress, 0) / 100));
}
注意:var(--progress) 必须参与计算,不能直接赋给 stroke-dashoffset,因为后者不接受百分比或无单位数值。
避免 transition 在重绘时跳变
如果只靠 CSS transition 动画 stroke-dashoffset,初始值和目标值一旦突变(比如从 30% 突然设为 80%),浏览器会按线性插值过渡,导致“倒退”或“绕圈”错觉。这不是 bug,而是 dashoffset 数值减小 → 路径起点右移 → 视觉上像逆向绘制。
解决方法只有两个:
- 用 JS 控制每次更新前先重置
stroke-dashoffset到起始位置(如251.2),再设新值并触发 transition - 改用
@keyframes+animation,把整个过程封装成从 0% 到目标值的单向动画,避免中间状态干扰
推荐后者,更可控。例如定义动画:
@keyframes draw {
to { stroke-dashoffset: calc(251.2 - (251.2 * var(--progress, 0) / 100)); }
}
svg circle { animation: draw 0.4s ease-out forwards; }
兼容性陷阱:IE 不支持 calc() 里嵌 var()
IE 完全不识别 var(),且旧版 Edge 对 calc(var()) 支持极差。如果项目还需兼容 IE,必须放弃纯 CSS 方案,改用 JS 直接设置内联样式:
el.style.strokeDashoffset = 251.2 - (251.2 * progress / 100) + 'px';
同时保留 CSS 自定义属性仅作状态标记(如 el.style.setProperty('--progress', progress)),方便调试或后续扩展。
另一个坑是 Safari 15.4 之前对 SVG 中 stroke-dashoffset 的 transition 支持不稳定,偶发卡顿。建议加 transform: translateZ(0) 强制 GPU 加速。
动态加载场景下如何响应式更新 --progress
真实加载中,进度往往由异步任务(如 fetch 的 onprogress)或轮询接口返回。此时不要在每次回调里反复调用 element.style.setProperty,尤其当频率 > 60fps 时,会造成样式重算压力。
更合理的方式是:
- 用
requestAnimationFrame节流更新,每帧最多同步一次 - 只在进度变化 ≥ 1% 时才触发样式更新(避免视觉无感的抖动)
- 动画结束时手动清除
--progress或设为100,防止残留值影响下一次使用
示例节流逻辑:
let pending = false;
function updateProgress(val) {
if (pending) return;
pending = true;
requestAnimationFrame(() => {
el.style.setProperty('--progress', Math.round(val));
pending = false;
});
}
真正难的不是画出圆环,而是让每一次数值变化都对应准确的视觉节奏,且不被浏览器重排打断。自定义属性在这里只是个“传声筒”,背后全是 timing 函数、重绘边界和 SVG 渲染管线的博弈。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











