← HTML 表单:从控件到提交与校验 / 三个显示型元素:output / progress / meter 待审核 11 / 24
output · progress · meter

三个显示型元素:output / progress / meter

表单不止于收集输入。规范在 4.10 一并定义了三个面向显示的元素:<output> 把计算或用户操作的结果讲给人(和辅助技术)听;<progress> 表示一项任务的进度<meter> 表示已知范围内的标量量规。三者最常见的误用是把后两者搞混——progress 描述「事情做了多少」,meter 描述「某个量当前是多少」。本页逐个上手,并把它们与 <form> 元素的关系点清楚。

1 · <output>:一个会被播报的结果区

<output for="a b" name="result"> 表示一次计算的结果。它默认是一个 live region(隐含 ARIA role=statusaria-live=polite):当其文本变化时,屏幕阅读器会在空闲时主动播报新值。for 列出参与这次计算的控件 id(以空格分隔,IDL 端是 .htmlFor,一个 DOMTokenList);内容通过 .value 读写,.defaultValue 记下初值供表单 reset 时还原。下面拖两个滑块,求和会实时写进 output

<output> 是 labelable、listed、resettable,但不是 submittable。它会出现在 form.elements 里、也能被 <label> 关联、表单 reset 时还原成 defaultValue;但它不进 entry list——即便写了 name,提交时 FormData 里也没有它的值。它是给人看的结果,不是要回传的数据。

2 · <progress>:任务进度,允许「不确定」

<progress value max> 表示一项任务完成了多少(如下载、上传)。给了 value 就是确定进度(determinate),浏览器按 value/max 画出占比;省略 value 则进入 indeterminate 状态——任务在跑、但说不清进度,浏览器画一条动态条。IDL 端:.value / .max,以及只读的 .position(确定时是 01{0-1} 的占比,indeterminate 时固定为 -1)。

progress 不是量规。它没有 min、没有 low / high / optimum,也没有颜色语义——它表达的是「朝着完成推进」这件事。拿 progress 去显示「磁盘占用 80%」是误用:磁盘占用是一个静态标量,不是一项正在推进的任务,那是 meter 的活。

3 · <meter>:已知范围内的标量量规

<meter value min max low high optimum> 表示一个落在已知区间 [min, max] 内的标量:磁盘占用、评分、电量、CPU 负载。它和进度无关——不暗示「正在朝某处推进」,只回答「这个量当前算好还是差」。阈值 low / high 把区间切成低 / 中 / 高三段,optimum 落在哪一段就把那段定为「好」(绿);与「好」相邻的段是「一般」(黄),再远的那段是「差」(红)。下面拖 value,并切换 optimum,看同一个 value 在不同 optimum 下被判成完全不同的颜色。

颜色不看绝对大小,只看「离 optimum 那段有多远」。同一个 value=50(落在中段):当 optimum=90(在 high 段)时,中段与 high 相邻 → 判为;当 optimum=50(也在中段)时,中段即「好」段 → 判为绿。这正是 meterprogress 的本质差别:meter 携带「好坏」的价值判断,progress 只有「多少」。

维度 <progress> <meter>
语义 任务进度(朝完成推进) 范围内的标量量规(当前是多少)
典型用例 下载 / 上传 / 安装百分比 磁盘占用、评分、电量、负载
区间下界 隐含 0无 min min(默认 0)与 max(默认 1)
阈值 / 颜色语义 low / high / optimum,无好坏色 low / high / optimum 三者共同划绿 / 黄 / 红
indeterminate 支持:省略 value → 动态条,.position = -1 不支持value 默认回退为 min
关键 IDL .value / .max / .position .value / .min / .max / .low / .high / .optimum

4 · 三段源码并排

三个显示型元素各司其职:

<!-- output:计算结果,live region,不进提交 -->
<form>
  <input type="range" id="a" /> + <input type="range" id="b" />
  = <output for="a b" name="result">0</output>
</form>

<!-- progress:任务进度。省略 value = indeterminate -->
<progress value="30" max="100"></progress>   <!-- 30% -->
<progress max="100"></progress>              <!-- 不确定,position = -1 -->

<!-- meter:范围内的标量量规,有颜色语义 -->
<meter min="0" max="100"
       low="30" high="70" optimum="90"
       value="55"></meter>   <!-- 55 在中段,optimum 在 high 段 → 黄 -->

progress 不是 metermeter 不是进度条。最常见的两类误用:其一,用 <progress> 显示「磁盘已用 80% / 评分 4.2」这类静态标量——它们不是正在推进的任务,该用 <meter>;其二,用 <meter> 显示下载进度——meter 的绿 / 黄 / 红价值色会误导用户以为「进度低 = 出问题」,该用 <progress>。选元素先问一句:这是「一件事做了多少」还是「一个量现在是多少」。

<output> 是显示而非数据。它在 form.elements 里、能被 reset 还原,但不参与提交(不进 entry list)。需要把计算结果回传服务器时,应另用一个 <input type="hidden"> 承载数据,<output> 只负责把同一个值讲给人听。表单归属、entry list 的判定见 <form> 元素

为什么 output 默认是 live region。它的隐含 ARIA role=status 带来 aria-live=polite:当你拖滑块、内容被改写时,屏幕阅读器会在用户停顿的间隙读出新结果,无需任何额外属性。这正是规范让它区别于一个普通 <span> 的地方——它天生就是「用来宣布结果」的元素。