标签需手动更新 value 值,不自动响应任务;适用于文件上传等有明确起止的场景,区别于表示静态占比的 ;须设 max,value 必为数字,应节流更新并确保终值准确。

progress 标签本身不自动更新,必须手动控制 value
<progress></progress> 是纯展示型 HTML 元素,它不会自己监听任务、计算进度或触发重绘。你看到的“实时”效果,全靠 JavaScript 主动修改 value 属性。常见错误是只写 HTML 就以为能动起来,结果页面上进度条始终卡在 0% 或默认值。
使用场景通常是:文件上传、数据加载、循环处理数组、fetch 请求分块响应等需要明确阶段反馈的操作。注意它和 <meter></meter> 的区别——<progress></progress> 表示「任务进行中」,有明确起点和终点;<meter></meter> 表示「当前值在某个范围内的占比」,比如磁盘使用率,不强调过程。
- 必须设置
max属性(默认为 1),否则value超过 1 会被截断,且部分浏览器渲染异常 -
value必须是数字,传字符串(如"50")会静默失败,进度条不动 - 不要用 CSS 动画“模拟”进度(比如
@keyframes从 0% 到 100%),这会误导用户,且无法与真实任务状态同步
如何安全更新 value:避免频繁重排与无效赋值
直接在循环里反复设 progress.value = i 看似简单,但可能触发大量 DOM 重排,尤其在高频率任务(如每毫秒更新)中造成卡顿。更糟的是,如果任务很快完成,中间大量 value 更新会被浏览器合并或丢弃,用户只看到跳变。
推荐做法是节流 + 边界控制:
- 用
requestAnimationFrame或setTimeout(..., 0)把更新“让出”给主线程空闲时机 - 只在进度变化超过 1%(或自定义阈值)时才写入
value,避免无意义更新 - 任务开始前设
progress.value = 0,结束时强制设为max,防止因舍入误差卡在 99%
例如处理 1000 项任务:
const progress = document.querySelector('progress');
const total = 1000;
progress.max = total;
<p>for (let i = 0; i </p><h3>兼容性与样式控制:IE 之外基本可用,但默认样式差异大</h3><p><code><progress></progress></code> 在 IE10+、Edge、Chrome、Firefox、Safari(macOS 6.1+/iOS 7+)均支持,无需 polyfill。但各浏览器默认外观差异明显:Chrome 显示蓝色条,Firefox 是绿色渐变,Safari 是灰色圆角条——不能指望它开箱即用就符合设计稿。</p><p>关键样式控制点:</p>
- 用
progress::-webkit-progress-bar和progress::-webkit-progress-value控制 Chrome/Safari 外观 - Firefox 用
progress::-moz-progress-bar - 不要尝试用
background直接覆盖整个<progress></progress>,会破坏内部结构,导致 value 不生效 - 若需高度定制(如环形、带文字),应改用
<div> + CSS/Canvas 实现,别硬改 <code><progress></progress>与 Promise / async 配合时,value 更新时机容易错位
异步任务中,常误把
progress.value++放在.then()外部,或在await后漏掉更新。更隐蔽的问题是:多个并发请求共用一个<progress></progress>,但每个请求不知道总任务数,导致max设错或value超限。典型修复方式:
- 先获取总任务量(如
GET /tasks?count-only),再发起批量请求 - 用
Promise.allSettled()收集全部结果后统一更新,或用计数器doneCount++每完成一项就更新value - 避免在
catch中跳过value更新——失败也是进度的一部分,可设为indeterminate或显示错误态
注意:
indeterminate(无确定进度)是布尔属性,设为<progress indeterminate></progress>即可,此时value会被忽略,适合仅需“正在处理”提示的场景。真正难的不是让进度条动起来,而是让它的数值和用户对任务的理解始终对齐——比如 80% 完成却卡住 30 秒,这时候进度条本身就成了干扰项。
- 先获取总任务量(如










