aria-valuemax 是原始数值上限而非百分比,必须与 aria-valuenow 单位一致;需显式设置 aria-valuemin 非零起点;更新时须校验范围并同步视觉宽度;原生 不应混用 aria 属性。

aria-valuemax 不是“最大百分比”,而是原始数值上限
它必须和 aria-valuenow 用同一套单位,比如文件上传总字节数、任务总耗时毫秒数、步骤总数。设成 100 是常见但错误的 shortcut——除非你的真实业务值就是 0–100 的整数序列。
- 上传 2MB 文件?
aria-valuemax="2097152"(2×1024×1024),aria-valuenow="1258291"(已传 1.2MB) - 表单共 7 步?
aria-valuemax="7",当前第 4 步就设aria-valuenow="4" - 后台任务预计 120 秒?
aria-valuemax="120000"(毫秒),而非100
强行归一化到 0–100 会导致精度丢失(如小数点后两位的进度)、调试困难(DevTools 里看到的值和后端日志对不上),且违反 ARIA 语义本意。
aria-valuemin 可省略,但显式写上更安全
aria-valuemin 默认为 0,多数场景下可以不写。但如果你的进度起点不是 0(比如任务从第 10 条数据开始处理),就必须显式设 aria-valuemin="10",否则读屏器会误判起始点。
- 只写
aria-valuenow="15"和aria-valuemax="100"→ 屏幕阅读器默认从 0 开始算,报“15%” - 实际范围是 10–100,应写
aria-valuemin="10"、aria-valuemax="100"、aria-valuenow="15"→ 报“第 15 条,共 100 条”或按比例换算 - JavaScript 更新前务必校验:
Math.min(max, Math.max(min, newValue))
动态更新时别用字符串,也别漏同步 width
aria-valuenow 和 aria-valuemax 都必须是数字类型,字符串(如 "100")在旧版 VoiceOver 或部分 Android TalkBack 中可能被忽略或截断为 0。
- ✅ 正确:
el.setAttribute('aria-valuenow', 82)或el.ariaValueNow = '82' - ❌ 错误:
el.setAttribute('aria-valuenow', '82%')、el.setAttribute('aria-valuemax', '100px') - 视觉进度条用
div实现时,el.style.width = (val / max) * 100 + '%'和el.setAttribute('aria-valuenow', val)必须同时执行——只动一个,读屏器和用户看到的就是两套进度
progress 元素里 max 和 aria-valuemax 别混用
<progress></progress> 自带语义,不需要也不该加 role="progressbar" 或任何 aria-* 属性。它的 max 就是标尺上限,和 aria-valuemax 无关联。
- 用原生
<progress value="3" max="5"></progress>→ 完全够用,无障碍支持开箱即用 - 自定义
<div role="progressbar"> → 才需要 <code>aria-valuenow+aria-valuemax,且二者缺一不可 - 混用(比如给
<progress></progress>加aria-valuemax)不仅多余,还可能干扰读屏器解析
最易被忽略的一点:当你用 JS 动态改 aria-valuenow,却忘了检查它是否仍在 aria-valuemin 和 aria-valuemax 范围内——超出范围时,NVDA 可能静默跳过,ChromeVox 会报错,而视觉上毫无提示。











