用径向渐变平铺实现小圆点装饰,轻量自适应;进度填充用css变量+calc()驱动linear-gradient或transform: scalex(),避免background动画卡顿。

用径向渐变画小圆点,别用一堆 <i></i> 标签
很多同学一看到带装饰点的进度条,第一反应是写十个 <i></i>,再用 flex 均分——能跑,但 DOM 膨胀、语义混乱、缩放后圆点间距还容易错乱。真正轻量且自适应的方式是用 CSS 径向渐变平铺:background: radial-gradient(circle at 8px 50%, #fff 2px, transparent 2px)。这个渐变本质就是一个“左偏 8px、垂直居中、半径 2px 的白色实心圆”,配合 background-size 控制平铺间距,就能自动填满整个容器宽度。
- 圆点位置由
circle at Xpx 50%决定,X 是圆心距左侧距离,不是圆点直径 -
background-size必须动态计算,比如--total: 12时,间距应为calc((100% - 16px) / (var(--total) - 1))(减去首尾两个圆心偏移) - 别把
background-size写死成40px 100%,否则在窄屏下会溢出或挤压变形 - 渐变色本身不参与进度逻辑,它只是轨道装饰;实际进度仍需靠另一个元素(如
.progress-bar)用width或transform控制
linear-gradient 做填充色,百分比得靠 JS 注入变量
想让渐变“停”在某个百分位(比如 65% 处截断),不能只写 linear-gradient(to right, #007BFF 65%, #eee 65%)——这会让颜色硬切,且 65% 是写死值,无法响应实时变化。正确做法是把进度值抽成 CSS 变量:--progress: 65,然后在背景中用 calc() 拼接:
background: linear-gradient( to right, #007BFF calc(var(--progress) * 1%), #eee calc(var(--progress) * 1%) );
- 必须写
calc(var(--progress) * 1%),不能省略* 1%,否则浏览器当无单位数字处理,渐变失效 - JS 更新时要用
el.style.setProperty('--progress', progress)(注意:这里传纯数字,不带%) - 如果直接写
el.style.setProperty('--progress', progress + '%'),再在 CSS 里用var(--progress),会导致语法错误——CSS 变量值带单位时,calc()里不能再乘1% - 这种方案在 Safari 15.4+ 和 Chrome 100+ 稳定,但 IE 完全不支持,降级需回退到传统
width方案
为什么不用 background-position 动态推渐变?
有人试过用 background-position: calc(var(--progress) * 1%) 0 配合一个超宽渐变图(比如 1000px 宽的左右双色条)来模拟进度,理论上可行,但实际踩坑多:
- 渐变背景图宽度必须远大于容器,否则
background-position推到尽头就露底色 - 移动端缩放或字体变化时,
calc()里的百分比基准会随视口抖动,导致进度“跳帧” - 安卓旧 WebView 对
background-position+calc()组合支持不稳定,常卡在初始位置不动 - 性能上不如直接改
width或transform: scaleX(),因为background-position触发的是重绘(repaint),不是合成层加速(compositor)
动画卡顿?优先换 transform,别硬推 background
渐变做进度填充时,如果加了 transition: background 0.3s ease,多数情况会掉帧,尤其在低端 Android 机上。根本原因是背景渐变动画无法走 GPU 合成,每次变化都触发整层重绘。更稳的解法是:把渐变画在伪元素上,用 transform: scaleX() 缩放它。
.progress-track::before {
content: '';
position: absolute;
top: 0; left: 0; bottom: 0;
width: 100%; height: 100%;
background: linear-gradient(to right, #007BFF, #eee);
transform-origin: left;
transition: transform 0.3s ease-out;
}
.progress-track.active::before {
transform: scaleX(0.65);
}
-
transform走合成层,不触发布局(layout)和重排(reflow),60fps 更有保障 - 务必设
transform-origin: left,否则缩放中心默认在中间,进度会从中间向两边展开 - JS 控制时,直接操作
el.style.transform = 'scaleX(' + progress/100 + ')',比反复 setProperty 更快 - 注意:
scaleX(0)会让伪元素完全不可见,若需显示 0% 状态,建议用opacity: 0单独控制显隐
渐变实现自适应进度条最易被忽略的一点:它从来不是独立解决方案。你总得搭配一个真实反映数据的机制——要么用 JS 实时写 style.width,要么用变量驱动 calc(),要么用 transform 映射比例。渐变本身只是“画布”,不是“控制器”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











