SVG+stroke-dashoffset是最稳的环形百分比实现方式,需明确r值、计算周长、设stroke-dasharray为周长、stroke-dashoffset= circumference×(1−p),并加transform="rotate(-90 50 50)"确保0%从顶部开始。

SVG + stroke-dashoffset 是最稳的环形百分比实现方式
直接用 stroke-dashoffset 控制 SVG <circle></circle> 的显示长度,是当前兼容性最好、行为最可控的方案。它不依赖 JS 动画循环,也不受 Canvas 渲染帧率或 CSS transform 抗锯齿影响,安卓 WebView、iOS Safari、Edge 都能一致表现。
关键不是“怎么画圆”,而是怎么让圆“从 0% 开始、顺时针填满”。常见错误是漏掉两件事:transform="rotate(-90)" 和动态周长计算。
-
r值必须明确(比如r="45"),否则stroke-dasharray无法对齐 - 周长必须算准:
circumference = 2 * Math.PI * r(r=45 → ≈282.74,常取283) -
stroke-dasharray设为周长值,stroke-dashoffset初始设为相同值(全隐藏) - 必须加
transform="rotate(-90 50 50)"(数字 50 对应cx/cy),否则 0% 出现在右侧而非顶部
百分比转 dashoffset 的公式别写错
进度显示错位,90% 是因为把公式记反了。不是 offset = p * circumference,而是:
stroke-dashoffset = circumference * (1 - p),其中 p 是小数形式(如 65% → 0.65)
立即学习“前端免费学习笔记(深入)”;
所以:
- 0% →
offset = circumference * 1 = 283(完全隐藏) - 65% →
offset = 283 * 0.35 ≈ 99(显示约 65%) - 100% →
offset = 0(完全显示)
注意:值越小,显示越长;写成 offset = p * circumference 会导致进度条反向收缩,看着像在“倒退”。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
纯 CSS conic-gradient 方案要注意浏览器支持
如果项目只面向现代浏览器(Chrome 89+、Firefox 85+、Safari 15.4+),conic-gradient 是最轻量的方案:无 SVG 标签、无 JS 计算、CSS 自动响应变量变化。
但容易踩的坑很具体:
- 必须写
from -90deg,否则 0% 从正右方开始,视觉上像缺了一块 - 容器必须有明确且相等的
width和height(比如120px),并设border-radius: 50% - 角度要用
calc(var(--p) * 3.6),不能带%单位(3.6 = 360 / 100) - IE 和 Safari ≤15.3 会完全不渲染,得用
@supports (background: conic-gradient())降级到 SVG
示例内联样式:style="--p: 72; background: conic-gradient(from -90deg, #4a9eff 0%, #4a9eff calc(var(--p) * 3.6deg), transparent calc(var(--p) * 3.6deg))"
Canvas 实现要绕开 requestAnimationFrame 陷阱
Canvas 虽灵活,但做“静态百分比环”反而容易过重。很多人一上来就用 requestAnimationFrame 做动画,结果页面卡顿、CPU 占用高,而实际需求只是“显示 78%”——根本不需要动。
正确做法是:只调用一次 ctx.arc(),传入终点角 endAngle = startAngle + 2 * Math.PI * p(p 为小数),然后 stroke()。
- 起点角推荐设为
-Math.PI / 2(即顶部),避免手动旋转 canvas - 别用
clearRect()频繁擦除——静态显示时完全不需要 - 如果后续要支持动画,再加
requestAnimationFrame,但初始渲染务必一步到位 - Canvas 文字居中要手动算基线:
ctx.textAlign = 'center'; ctx.textBaseline = 'middle'
Canvas 的优势在于自定义描边渐变、阴影、多层叠加,而不是替代 SVG 做基础环形进度。
真正难的不是“怎么画出来”,而是“怎么让 65% 在所有设备上都精确停在同一个角度位置”。SVG 的 dashoffset 和 CSS 的 conic-gradient 都依赖数学一致性,一旦半径、起点、单位三者有一处没对齐,环就偏了——这种偏差在 Retina 屏或缩放页面里会被放大,但很难一眼看出原因。


















