svg圆形进度条需用配合stroke-dasharray(设为周长,如314.16)和stroke-dashoffset(从周长值递减至0)实现,须加transform="rotate(-90)"对齐顶部起点,仅对stroke-dashoffset做css过渡动画以确保顺时针平滑填充。

零基础也能直接用,但别指望复制粘贴就完全适配——SVG + CSS 实现的圆形进度条,核心在 stroke-dasharray 和 stroke-dashoffset 的配合,不是改个数字就能动起来。
为什么用 <svg></svg> 而不是 <div> + <code>border-radius
纯 CSS 圆形进度条(比如用伪元素旋转遮罩)控制精度差、动画卡顿、无法响应式缩放;SVG 天然支持路径长度计算和属性动画,且兼容性好(IE9+)。关键点在于:<circle></circle> 的周长必须手动算,不能靠 getTotalLength() 后再 JS 获取——零基础容易在这一步卡住。
-
r="50"时,周长 =2 * Math.PI * 50 ≈ 314.16,直接写死为stroke-dasharray="314.16" - 进度 60% → 剩余未填充部分 =
314.16 * (1 - 0.6) = 125.66,设为stroke-dashoffset="125.66" - 不要用百分比单位填
stroke-dashoffset,它只认像素或无单位数值
stroke-dashoffset 越大,进度反而越小?
这是最常反直觉的坑:偏移量是从路径起点(默认 3 点钟方向)逆时针“推走”实线段。所以 stroke-dashoffset 从 0 增加到 314.16,相当于把整圈实线逐步“推离”视野,看起来就是进度从 100% 降到 0%。
- 要实现「0% → 100%」增长,CSS 动画得让
stroke-dashoffset从314.16线性减到0 - 若用 JS 控制,记得每次更新都重新计算:
offset = circumference * (1 - progress) - 别忘了给
<circle></circle>加transform="rotate(-90)",否则 0% 起点在 3 点钟,不符合常规「12 点钟开始顺时针填充」习惯
如何让进度值动态传入 HTML 并实时更新?
零基础最容易硬编码写死 stroke-dashoffset,但实际项目需要 JS 注入。安全又简单的做法是:HTML 里留 data-progress="75",JS 读取后算偏移量,再设内联样式。
<svg viewbox="0 0 120 120"><circle cx="60" cy="60" r="50" fill="none" stroke="#e0e0e0" stroke-width="8"></circle><circle cx="60" cy="60" r="50" fill="none" stroke="#4caf50" stroke-width="8" stroke-dasharray="314.16" stroke-dashoffset="314.16" data-progress="75"></circle></svg>
- 用
document.querySelector('circle[data-progress]')拿到元素 -
const progress = parseFloat(circle.dataset.progress) / 100,注意除以 100 - 设置
circle.style.strokeDashoffset = circumference * (1 - progress) - 别用
setAttribute('stroke-dashoffset', ...),CSS 动画会失效
真正难的不是画圆,而是理解「路径长度」和「视觉偏移」的数学关系;一旦算错周长或符号搞反,进度条要么不动、要么转半圈、要么从中间裂开——这些都不是代码写错了,是没想清楚 SVG 坐标系怎么数的。











