滚动圆形进度环特效(容器滚动百分比圆环,颜色实时可调)
滚动圆形进度环:SVG 圆环实时显示容器滚动进度,中心百分比可隐藏,圆环颜色实时可调,支持整页与任意容器滚动,零依赖自研实现。
效果演示(真实可交互)
⭕ 在下方容器内滚动:右上角圆环实时显示阅读进度
《长页面动效设计指南》节选
当页面足够长时,用户会本能地想知道「我读到哪了、还剩多少」。线性进度条常见,但圆形进度环更适合放在角落或侧边,占用空间更小,形态也更精致。
圆形进度环的实现只需要一个 SVG 圆:把 `stroke-dasharray` 设为圆的周长,滚动时按进度比例缩短 `stroke-dashoffset`,笔画就像被「擦掉」一样呈现剩余量。
第一条原则:数值真实。进度必须与滚动位置严格同步,任何滞后都会让用户失去信任。每帧只更新一次 dashoffset,避免浮点抖动。
第二条原则:视觉克制。圆环细、颜色跟随品牌色,中心百分比数字字号小一号;过度装饰反而喧宾夺主。
第三条原则:性能友好。滚动回调里只做数学计算和一次属性写入,不操作 DOM 布局属性;SVG 属性动画走合成层,开销可忽略。
第四条原则:场景适配。整页滚动用 `window`,局部容器(本演示)用容器元素;还可以把圆环换成「圆形按钮」,点击回到顶部。
第五条原则:可访问性。装饰性圆环应加 `aria-hidden="true"`,百分比文字用真实文本而非图片,屏幕阅读器也能读到进度。
第六条原则:移动端。触屏滚动同样触发 scroll 事件,同一套代码覆盖桌面与移动端;注意 iOS 橡皮筋下 scrollTop 为负,要做下限保护。
演示区右上角的圆环实时反映左侧滚动容器的阅读进度。圆环颜色与中心百分比均可通过下方控件调节。正式使用时把监听对象换成
window即可作用于整页。
完整代码
<svg class="ring" viewBox="0 0 120 120">
<circle class="track" cx="60" cy="60" r="52" />
<circle class="bar" id="bar" cx="60" cy="60" r="52" />
</svg>
.bar {
fill: none;
stroke: #6c8cff;
stroke-width: 6;
stroke-linecap: round;
stroke-dasharray: 326.7; /* 圆周长 2πr */
stroke-dashoffset: 326.7; /* 初始完全隐藏 */
}
const CIRC = 2 * Math.PI * 52;
function update() {
const max = scroller.scrollHeight - scroller.clientHeight;
const pct = max > 0 ? Math.max(0, scroller.scrollTop) / max : 0;
bar.style.strokeDashoffset = (CIRC * (1 - pct)).toFixed(1);
}
scroller.addEventListener('scroll', update, { passive: true });
实现要点:圆的 stroke-dasharray 等于周长,滚动进度为 p 时把 stroke-dashoffset 设为 周长 × (1 - p),笔画按比例「露出」,看起来就像圆环被逐渐填满。SVG 加 transform: rotate(-90deg) 让起点位于正上方,更符合进度环习惯。
参数说明
| 参数 | 位置 | 说明 |
|---|---|---|
| 圆环颜色 | stroke 属性或控件 | 品牌色即可,渐变可用 SVG 线性渐变 |
| 笔画粗细 | stroke-width: 6 | 4-8 之间,越细越精致 |
| 中心文字 | #spcNum 元素 | 百分比或隐藏,二选一 |
| 圆环半径 | r="52" | 改半径时同步更新周长常量 |
| 监听对象 | window / 容器元素 | 整页或局部容器滚动 |
兼容性与性能
- 滚动回调只做一次减法乘法和一次
strokeDashoffset写入,SVG 属性动画在合成器处理,开销可忽略 - 监听器使用
{ passive: true },不阻塞滚动线程;toFixed(1)避免浮点抖动造成的笔画闪烁 - 进度计算带
max > 0与Math.max(0, ...)双重保护,内容不满一屏或 iOS 橡皮筋回弹时都不会出现异常值 - 全浏览器兼容(Chrome / Safari / Firefox / Edge / iOS / Android),SVG 原生支持,无需任何 polyfill
常见问题
Q: 圆环不转、一直是空的? 大概率是 stroke-dasharray 与半径不匹配:半径 52 时周长是 326.7,改过半径记得同步更新两个值,否则进度比例会错乱。
Q: 想让它转起来而不是「被填满」? 那是另一类效果。本组件的「填满」语义更适合进度;若想要旋转装饰,请把动画放在 transform: rotate() 上而非 dashoffset。
Q: 圆环可以点击回到顶部吗? 可以。给 .spc-ringbox 加 cursor: pointer 与 click 监听,调用 scroller.scrollTo({ top: 0, behavior: 'smooth' }) 即可,视觉上还能加悬停放大。
Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名,无任何协议限制。
许可与来源
- 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
- 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
- 首次发布:2026-09-01 · 最近更新:2026-09-01
- 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
- 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理
常见问题
这个组件可以商用吗?
可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。
浏览器兼容性如何?
支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。
怎么修改动画参数?
直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。