svg 配合 stroke-dasharray 和 stroke-dashoffset 是兼容性最好、精度最高、动画最可控的环形进度图方案,需动态计算周长、正确设置偏移量、使用 viewbox 实现响应式缩放,并注意深色模式、移动端适配及文字居中等细节。

用 SVG <circle></circle> 实现环形进度图最可靠
纯 CSS 方案(比如用 border-radius + transform 旋转遮罩)在 Safari 和旧版 Edge 上容易失准,且无法精确控制起始角度和动画缓动。SVG 的 <circle></circle> 配合 stroke-dasharray 和 stroke-dashoffset 是目前兼容性最好、精度最高、动画最可控的方式。
关键点在于:先画一个完整圆环(stroke),再用虚线长度(stroke-dasharray)设为周长,偏移量(stroke-dashoffset)决定“未填充”部分长度。进度 0% → 100% 对应 offset 从周长 → 0。
-
cx/cy决定圆心位置,别硬写死像素值,建议用百分比或配合viewBox - 周长 =
2 * Math.PI * r,必须用 JS 动态算,不能手写 125.66 这类近似值(否则缩放时错位) - 动画推荐用
transition直接作用于stroke-dashoffset,比@keyframes更顺滑、更易控制暂停/重置
如何让环形进度图响应式缩放不糊
直接给 <svg></svg> 设 width/height 百分比 + viewBox 是唯一稳妥方案。漏掉 viewBox 或只设 width 不设 height,会导致拉伸变形或模糊。
示例 viewBox:viewBox="0 0 100 100",然后把圆的 r="45"、cx="50"、cy="50" 全部按这个坐标系写。外部容器控制大小,SVG 内部保持比例不变。
- 禁止用
transform: scale()缩放整个 SVG —— 文字会糊,描边会粗细不均 - 如果要适配深色模式,别改
stroke颜色,用CSS custom property+currentColor更灵活 - 移动端需加
touch-action: none防止拖拽误触发
stroke-dashoffset 计算错误导致进度卡在 0% 或 100%
这是最常踩的坑:offset 值没随进度动态更新,或初始值设错。常见错误包括:
- 忘记把
stroke-dasharray设为周长,比如写成"100"而不是"282.74"(r=45 时) - progress = 0.7 时,offset 错写成
0.7 * circumference(应是(1 - 0.7) * circumference) - JS 更新 offset 前没先设置
stroke-dasharray,导致第一次渲染无动画
安全写法(含防 NaN):
const radius = 45; const circumference = 2 * Math.PI * radius; const offset = circumference - (progress * circumference); el.style.strokeDashoffset = isNaN(offset) ? 0 : offset;
需要文字居中显示进度百分比?别用 text-anchor 硬调
用 <text></text> 标签直接写数字,x="50%" y="50%" 加 dominant-baseline="middle" text-anchor="middle" 最稳。但注意:若 SVG 有 transform 或父容器有 font-size 缩放,文字可能偏移。
- 文字字号建议用
em或rem,避免固定px导致小屏看不清 - 百分比数字建议用
Math.round(progress * 100),别直接progress.toFixed(0)(0.999999 会变成 99) - 如需支持多语言(比如中文“完成”),文字内容应由外部传入,而非写死在 SVG 里
真正难的不是画出圆环,而是让同一份代码在 Chrome/Firefox/Safari/iOS WebView 里都对齐、不跳帧、不模糊——这些细节堆起来,才是组件能上线的关键。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











