标签不适用于阅读进度,因其语义为任务完成度,需手动更新 value 且无自动滚动监听;真实场景应优先用 div + aria 实现高性能、高兼容、语义准确的阅读进度条。

直接用 <progress></progress> 标签加几行 CSS 就能跑起来,但用户滚动时进度跳变、视觉滞后、移动端卡顿——这些才是真实体验卡点。别先写 JS,先确认你是否真需要“阅读进度”这个语义。
progress 标签在阅读场景中是否适用
<progress></progress> 的语义是「任务完成度」,比如上传、安装、表单步骤;而页面阅读是连续、无明确终点、不可预测长度的行为。浏览器不会自动监听 scroll 或计算可视区域占比,它只响应你手动设置的 value。强行套用会导致:屏幕阅读器读出“已加载 37%”,但用户根本没触发任何任务。
- 如果你只是想展示「当前滚动到文档哪一屏」,
<progress></progress>不是原生解法,得靠 JS 计算 - 如果页面内容固定(如长文教程、PDF 导出页),且你控制了总高度(比如
document.body.scrollHeight),那它可以作为容器,但必须自己驱动value - 不支持 IE,且 Safari 对
progress的伪元素支持最弱,若需圆角+渐变+阴影,Chrome/Firefox/Safari 三端样式要分别写
用 scroll 事件实时计算阅读进度的坑
监听 window.onscroll 或 addEventListener('scroll', ...) 看似简单,但高频触发 + 同步 DOM 读取会直接拖慢滚动帧率,尤其在低端 Android 设备上明显掉帧。
- 必须节流:用
requestAnimationFrame包一层,而不是setTimeout或 Lodash 的throttle - 别反复调用
document.documentElement.scrollTop和document.body.scrollHeight—— 这些是强制重排(reflow)操作,缓存它们的值 - 移动端 iOS Safari 有“滚动粘滞”行为:
scrollTop在手指抬起前可能不更新,导致进度条卡在 98% 不动;应改用getBoundingClientRect().top监听首屏元素位置 - 不要把进度条宽度设为
style.width = x + '%',而要用transform: scaleX(x/100),避免触发布局重排
CSS 自定义 progress 条的跨浏览器写法
只写 progress { width: 100%; height: 4px; } 是无效的——它只控制外框,内部填充条由伪元素控制,且各浏览器命名不一致。
- Chrome / Edge / Safari(WebKit):
progress::-webkit-progress-bar控制轨道,progress::-webkit-progress-value控制已填充部分 - Firefox:
progress::-moz-progress-bar是唯一可用伪元素,无法单独控制轨道背景 - 所有浏览器都支持
progress { appearance: none; },但 Firefox 下设了也未必生效,建议加!important - 想让进度条带圆角?必须给
::-webkit-progress-value和::-moz-progress-bar都设border-radius,否则 Safari 圆角、Firefox 方角 - 不要用
background-image: linear-gradient(...)给::-webkit-progress-value,iOS Safari 16+ 才支持,旧版会 fallback 到纯色
更轻量的替代方案:div + ARIA
当兼容性、性能或语义准确性压倒原生标签优势时,用 <div role="progressbar" aria-valuenow="32" aria-valuemin="0" aria-valuemax="100"></div> 更可控。
- 你可以自由用
clip-path做弧形进度、用mask-image做镂空效果,<progress></progress>不支持这些 - JS 更新时只需改
el.setAttribute('aria-valuenow', 45)和el.style.transform = 'scaleX(0.45)',无浏览器兼容风险 - 保留无障碍能力:VoiceOver、TalkBack 仍能正确播报进度百分比
- 如果项目已用 Tailwind,一行
h-1 bg-blue-500 rounded-full origin-left scale-x-0 transition-transform duration-300比写三套伪元素快得多
真正难的不是让进度条动起来,而是让它动得准、动得顺、动得不骗人——比如用户快速滚动时,进度值不能超前于视觉位置;比如页面有 sticky header,scrollTop 要减去 offset 才真实;比如用户切到后台再切回,scroll 事件不触发,但进度条得续上。这些细节不写进代码注释里,下次维护的人会花两小时 debug。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











