标签仅显示进度,需JavaScript动态更新value值;value超max或为负数时无效,省略value则呈不确定状态;IE11及更早版本不支持;更新需防高频重绘,应加阈值和取整;多任务须按字节加权计算;必须同步设置ARIA属性以保障可访问性;样式定制依赖带前缀的伪元素;核心难点在于准确定义“100%”的业务含义。

<progress></progress> 标签本身不驱动进度,它只是个“显示器”——value 变了,它才动;value 不变,它就卡住。别指望写个 <progress value="30" max="100"></progress> 就自动跑起来。
为什么<progress></progress>没反应?常见赋值错误
直接在 HTML 里写死 value,但没用 JS 更新,进度条就是静态的。更隐蔽的问题是:
-
value超出max(比如value="120" max="100"),浏览器会忽略该值,显示为 0% 或空白 -
value为负数(如value="-5"),同样被丢弃,不报错但不渲染 - 省略
value属性(<progress max="100"></progress>),进入不确定状态(indeterminate),表现为循环动画,不是数字进度 - 在 IE11 及更早版本中,
<progress></progress>标签完全不解析,页面上啥也不显示
动态更新必须用 JavaScript,但别高频写 value
每次调用 progress.value = newValue 都会触发样式重计算和重绘。低端设备上,每 30ms 更新一次就可能掉帧。
- 用
Math.round()对齐整数百分比,避免小数频繁变化:el.value = Math.round(loaded / total * 100) - 加一层“变更阈值”:仅当新值与当前
value相差 ≥ 1 时才写入 DOM - 上传/下载场景优先监听原生事件:
xhr.upload.onprogress或ReadableStream的 chunk 处理,而不是用setInterval模拟 - 若需平滑动画,CSS 中给
progress::-webkit-progress-value和progress::-moz-progress-bar加transition: width 0.2s ease(注意 Firefox 不支持 width 过渡,实际靠重绘帧模拟)
多任务合并进度不能简单除法
3 个文件上传,完成 2 个 ≠ 66%。如果文件大小分别是 1MB、100MB、5MB,按数量平均分配会严重误导用户。
立即学习“前端免费学习笔记(深入)”;
- 正确做法是按字节加权:
globalTotal = sum(task.total),globalLoaded = sum(task.loaded),再算Math.min(100, Math.round(globalLoaded / globalTotal * 100)) - 某个任务失败且不再重试时,不要冻结
value,而应同步更新aria-valuetext为 “第 2 项失败,共 3 项,2 项完成” - 永远同步设置 ARIA 属性:
el.setAttribute('aria-valuenow', current)、el.setAttribute('aria-valuemin', 0)、el.setAttribute('aria-valuemax', 100)、el.setAttribute('aria-valuetext', `${current}% 完成`)—— 缺一不可,否则屏幕阅读器读不出进度
CSS 自定义样式必须用伪元素,且写全前缀
直接对 progress 设 background 或 height 是无效的,因为内部结构被 Shadow DOM 封装。
- Chrome/Edge/Safari(WebKit)需用:
progress::-webkit-progress-bar(背景)、progress::-webkit-progress-value(填充色) - Firefox 只认:
progress::-moz-progress-bar(填充色,背景无法单独控制) - 高度控制统一写在
progress本身:progress { height: 6px; },再配合overflow: hidden防溢出 - 圆角、渐变、阴影都得分别写进对应伪元素,不能只写一个浏览器前缀
真正难的不是画出那根条,而是定义清楚“100% 到底意味着什么”——是所有请求返回?是所有字节写入磁盘?还是用户可交互状态就绪?这个逻辑一旦错位,再漂亮的进度条也只是障眼法。



















