svg圆形进度条必须用配合stroke-dasharray和stroke-dashoffset实现,因transform: rotate遮罩方案易错位、精度差且不兼容旧版safari/安卓webview;需rotate(-90deg)校正起点至12点方向,周长须精确计算为2 math.pi r,并用数值而非百分比设置dasharray与dashoffset,配合will-change: transform触发gpu加速以避免跳变。

SVG 是目前最可靠、兼容性最好、控制最精确的 HTML 进度环实现方式,纯 CSS(如 conic-gradient 或旋转遮罩)在 Safari 旧版、部分安卓 WebView 中存在错位、不渲染或精度丢失问题,不建议用于生产环境中的关键进度展示。
为什么必须用 circle + stroke-dasharray 而不是 transform: rotate 模拟
transform: rotate 方案本质是“遮罩+旋转”,需拆分左右半圆、用 overflow: hidden 截断,结构脆弱、缩放易错位、线宽对齐难,且无法精确到 1% —— 比如 99% 和 100% 在视觉上几乎无差别。而 stroke-dasharray 直接控制描边长度,数值与百分比一一对应,误差可控制在亚像素级。
- stroke-dasharray="314.16" 表示“画一段 314.16px 的实线,后面全是空白”
- stroke-dashoffset 决定从哪开始画:值越小,露出越多;设为 0 就是满环
- 必须配合 transform="rotate(-90)",否则起点在 3 点钟方向(默认),不符合人眼习惯
如何避免 SVG 进度环在移动端跳变或不动
iOS 15 以下、部分安卓 WebView 中,transition: stroke-dashoffset 不触发硬件加速,看起来就是突变,而非平滑动画。
- 别把 transition 写在 CSS 类里,改用内联样式:style="transition: stroke-dasharray 0.3s ease, stroke-dashoffset 0.3s ease;"
- 更稳妥的做法是不用 CSS 过渡,改用 requestAnimationFrame 手动插值更新 setAttribute('stroke-dashoffset', value)
- 缓存周长计算:不要每次重算 2 * Math.PI * r,提前存为常量,避免浮点误差导致收口不严
- r、cx、cy 值必须和 viewBox 匹配(如 viewBox="0 0 100 100" 时,cx="50" cy="50" r="45")
动态更新进度时最容易踩的三个坑
-stroke-dashoffset 的符号和方向反了:它不是“画多少”,而是“偏移多少”。60% 进度对应的是 offset = circumference * (1 - 0.6),不是 * 0.6
- 忘记加 transform="rotate(-90 50 50)"(第二个参数是中心坐标),导致进度从右边开始,用户第一反应是“这环转歪了”
- 直接写死 stroke-dasharray="314" 却没同步更新 stroke-dashoffset 的计算逻辑,一旦改了 r,所有进度都错位
复杂点在于:它看着只是画个圈,但每个数值都耦合着几何、坐标系、浏览器渲染管线。哪怕只是换一个 r,也得重算周长、重调 offset、重校 transform 中心点——没有“设完就跑”的环节,全得对齐。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











