SVG环形进度条通过stroke-dasharray与stroke-dashoffset协同控制视觉长度,配合rotate(-90)校正起点、CSS transition仅作用于stroke-dashoffset实现平滑动画,且需动态计算周长、统一设置linecap/linejoin及viewBox确保精度与响应式。

SVG环形进度条的核心在于用矢量路径的“裁剪+偏移”机制表达进度,不是靠JS逐帧绘制,而是靠stroke-dasharray和stroke-dashoffset两个属性协同控制视觉长度,再结合CSS过渡实现平滑动画。关键是要让数学计算与DOM结构、样式声明严格对齐,否则容易出现不动、错位或跳变。
圆周长必须动态算准,不能硬编码
进度表现是否准确,取决于圆周长值是否与实际半径严格匹配。公式是:circumference = 2 × π × r。比如半径设为70,周长就是2 × 3.1416 × 70 ≈ 439.82;若半径改为50,周长就得重算为314.16。硬写成“471”或“314”看似方便,但一旦r变动,进度百分比就会整体失真。
- 推荐在JS中统一计算:
const r = 70; const circumference = 2 * Math.PI * r; - 把
stroke-dasharray设为该值(如"439.82"),作为最大可显示长度 -
stroke-dashoffset初始值设为周长,表示进度0%时完全不可见
起点对齐顶部,必须加 rotate(-90)
SVG默认角度0°在正右方,直接画圆环会导致进度从右侧开始顺时针增长。要让进度从顶部开始(符合常规认知),必须将整个圆环逆时针旋转90度。最稳妥的方式是用<g transform="rotate(-90)">包裹<circle>,而不是只对单个元素加transform——这样能确保坐标系整体校正,避免后续动画偏移。
- 不要只给
<circle>加transform,易被其他样式覆盖 - 如果使用
viewBox(如viewBox="-50 -50 100 100"),建议圆心设为(0,0),配合rotate更干净 - 辅助底环和进度环都应放在同一
<g>内,保证旋转同步
CSS过渡只作用于 stroke-dashoffset
动画流畅的关键是仅对stroke-dashoffset做CSS transition,且必须写在元素内联style上(如style="transition: stroke-dashoffset 0.4s ease-out;")。浏览器无法对stroke-dasharray插值,若对其加transition,动画会卡顿或失效。
- JS更新时只改
stroke-dashoffset:偏移量 = 周长 × (1 − 进度 / 100) - 例如进度60%,offset = 439.82 × 0.4 ≈ 175.93
- 多个进度条批量更新时,先批量计算offset值,再统一setAttribute,避免强制同步重排
细节优化让线条更自然
粗线边缘发虚、接头生硬、缩放变形,往往源于几个小但关键的属性缺失:
- 加上
stroke-linecap="round",让圆环两端呈半圆收尾,视觉更饱满 - 加上
stroke-linejoin="round",避免转角处出现尖锐凸起 - 两层圆环(底环+进度环)用相同
r、cx、cy和stroke-width,仅颜色不同,确保精准重叠 - 容器用
viewBox替代固定宽高(如viewBox="0 0 160 160"),实现真正响应式缩放


















