滚动进度条必须用js计算window.scrolly / (document.documentelement.scrollheight - window.innerheight)并节流更新,因fixed元素width:100%仅相对于视口,无法反映真实滚动比例;需用requestanimationframe节流、缓存scrollheight、处理ios safari地址栏收放及不可滚动边界情况。

什么是 window.scrollY 和 document.documentElement.scrollHeight
彩色阅读进度条本质是根据用户当前滚动位置占全文高度的比例,动态更新一个顶部横条的宽度和颜色。关键不是“画一条线”,而是实时算出:window.scrollY(已滚动像素)除以document.documentElement.scrollHeight - window.innerHeight(可滚动总高度),得到 0~1 的进度值。
注意:document.body.scrollHeight 在某些 CSS 重置或 DOCTYPE 下不准,必须用 document.documentElement.scrollHeight;window.innerHeight 是可视区高度,不能漏减——否则进度会超过 100%。
用 position: fixed 实现顶部吸附条
进度条必须始终贴在视口顶部,且不随页面滚动偏移。最稳妥方式是用 position: fixed + top: 0,同时设置 z-index: 9999 避免被其他元素遮挡。
常见错误:用 position: sticky 或放在 <header></header> 内部——前者依赖父容器,后者会随页面滚动消失;用 absolute 更糟,完全脱离文档流且无法固定在视口顶。
推荐结构:
<div id="progress-bar" style="position: fixed; top: 0; left: 0; height: 4px; width: 0%; background: linear-gradient(90deg, #ff6b6b, #4ecdc4); z-index: 9999; pointer-events: none;"></div>
用 requestAnimationFrame 替代 scroll 事件监听
直接监听 scroll 事件会导致高频触发、卡顿甚至掉帧。浏览器每秒滚动可能触发上百次,但屏幕刷新通常只有 60fps,没必要每次都算。
正确做法是用 requestAnimationFrame 节流:只在下一帧绘制前读取一次滚动值,既平滑又省资源。
实操要点:
- 把滚动监听器设为
{ passive: true },避免阻止默认行为导致性能警告 - 不要在回调里直接改
style.width,先算好百分比,再一次性赋值 - 避免重复绑定——检查是否已存在
#progress-bar再创建
简短示例逻辑:
let bar = document.getElementById('progress-bar');<br>function updateProgress() {<br> const scrollY = window.scrollY;<br> const maxScroll = document.documentElement.scrollHeight - window.innerHeight;<br> const progress = Math.min(100, (scrollY / maxScroll) * 100);<br> bar.style.width = `${progress}%`;<br>}<br>function handleScroll() {<br> requestAnimationFrame(updateProgress);<br>}<br>window.addEventListener('scroll', handleScroll, { passive: true });
渐变色怎么随进度动态变化
纯 CSS 的 linear-gradient 无法动态改色停靠点,所以不能靠 CSS 动画模拟“流动感”。实际做法是:保持背景渐变不变,只改变 width;或者用 JS 计算当前进度对应的颜色值,再写入 bar.style.background。
如果要“随进度变色”(比如从红→黄→绿),推荐用 HSL 模式插值:
- 起始色:
hsl(0, 100%, 60%)(红) - 结束色:
hsl(120, 100%, 60%)(绿) - 当前色:
hsl(${progress * 120}, 100%, 60%)
这样比 RGB 插值更直观,也避免中间出现脏色。但注意:HSL 的 h 值超过 360 会自动归零,所以乘数别超 360。
真正容易被忽略的是:移动端 Safari 对 fixed 元素在滚动时的渲染有延迟,有时进度条会“跳变”。加一行 bar.style.will-change = 'width'; 能强制开启 GPU 加速,缓解该问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











