纯 CSS 实现页面顶部阅读进度条目前仅在支持 animation-timeline 的浏览器中可行,且需配合 scroll(y) 时间轴;绝大多数生产环境仍必须依赖 JavaScript 驱动宽度或缩放值,CSS 仅负责定位与视觉样式。

纯 CSS 实现页面顶部阅读进度条目前仅在支持 animation-timeline 的浏览器中可行,且需配合 scroll(y) 时间轴;绝大多数生产环境仍必须依赖 JavaScript 驱动宽度或缩放值,CSS 仅负责定位与视觉样式。
为什么不能只靠 position: fixed + width: 30%
fixed 定位的元素 width: 100% 是相对于视口宽度,不是页面总高度;滚动进度本质是 window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) 这个比值,CSS 无法读取这些动态 JS 变量。直接写死 width: 30% 得到的是静态条,和滚动完全无关。
- 常见错误:把
<div class="progress-bar"> 塞进 <code><main></main>里设position: absolute—— 一滚动就消失,因为定位上下文错了 -
position: sticky只能“粘”在某个临界位置,无法输出连续的 0%→100% 宽度变化 - 即使加了
transform: scaleX(),也得靠 JS 更新 scale 值,transform-origin只影响缩放基点(如设0 50%才是从左往右展开) - 仅 Chromium 125+、Firefox 127+、Safari 17.4+ 支持,iOS Safari 17.4 之前全不支持
- 必须将进度条容器设为
position: fixed; top: 0; left: 0; width: 100%; height: 2px;,否则时间轴绑定失败 - 动画只能作用于单个属性(如
width或transform),不能同时驱动宽度+百分比文字 - 无法处理边界情况:当页面不可滚动(
scrollHeight ≤ innerHeight)时,会卡在 NaN 或负值,JS 方案可主动 fallback 为0% - 滚动距离必须用
document.documentElement.scrollHeight,不是document.body.scrollHeight(后者在标准模式下常偏小) - 可滚动高度是
document.documentElement.scrollHeight - window.innerHeight,漏减window.innerHeight会导致满屏滚动时进度超 100% - 原生
scroll事件太密,必须用requestAnimationFrame节流,否则 iOS Safari 和 macOS 触控板上容易掉帧 - 移动端 Safari 地址栏收起/展开会改变
window.innerHeight,但window.scrollY不同步更新,必须监听resize重新校准缓存的maxScrollHeight
用 animation-timeline: scroll(y) 的前提和限制
这是目前唯一接近“纯 CSS”的方案,但实际落地门槛高:
JavaScript 必须参与的三个关键点
哪怕你只想用 CSS 控制样式,JS 仍是计算和更新的核心:
真正容易被忽略的不是怎么写 CSS,而是滚动计算中那几个看似微小的差值:少减一个 window.innerHeight,进度条就会溢出;缓存错一个 scrollHeight,快速滚动时条就“追不上”;没处理 resize,iOS 上地址栏切换后进度直接跳变。这些都不是样式问题,是 DOM 属性语义的理解偏差。











