原生 CSS 滚动驱动动画无法实现全局滚动进度条,因其 scroll() 时间线不提供可读取的滚动百分比值,且仅支持容器内滚动映射,无法绑定 width 或 scaleX;必须用 JS 计算 scrollTop/(scrollHeight-clientHeight) 并同步至 CSS 变量。

原生 CSS 滚动驱动动画(animation-timeline)目前**不能直接实现“页面滚动进度条”这种全局、覆盖式、随 document.scrollingElement 同步的进度指示器**。它只支持两种时间线:scroll()(容器内滚动)和 view()(元素进出视口),但二者都**不提供 0%→100% 的全局滚动比例作为可绑定数值**,更无法生成一个固定在视口顶部、宽度随滚动实时变化的横条。
为什么 animation-timeline: scroll() 不能做全局进度条
该语法必须绑定到一个**有明确滚动范围的容器**,比如 div.scroll-container。当你写 animation-timeline: scroll(root),它确实指向文档根滚动容器,但问题在于:
-
scroll()时间线本身不输出“当前滚动百分比”这个值,它只是把滚动位移映射为动画播放进度(0→1),但你无法用它去控制另一个元素的width或transform: scaleX()—— 因为 CSS 中没有类似scroll-progress()这样的函数可读取该值 - 即使你用
@keyframes定义了from { width: 0% }→to { width: 100% },这个动画只会从“容器开始滚动”播到“容器滚动到底”,而不会随用户实际scrollTop线性更新;它是一次性、不可逆、不可暂停的播放行为 - 多个元素共用同一
scroll(root)时间线时,动画起始/结束位置取决于各自在 DOM 中的位置,不是统一按文档总高计算的百分比
真正能做全局滚动进度条的方案只有 JS + CSS 组合
你需要手动计算 scrollTop / (scrollHeight - clientHeight),再将结果同步给 CSS 变量或元素样式。这是目前唯一可靠、可控、可调试的方式:
- 监听
scroll事件,但务必用requestAnimationFrame节流,避免 layout thrashing - 用
document.documentElement.scrollTop || document.body.scrollTop兼容各浏览器 - 推荐将进度值存入 CSS 自定义属性:
document.documentElement.style.setProperty('--scroll-progress', progress) - CSS 中用
width: calc(var(--scroll-progress) * 100%)或transform: scaleX(var(--scroll-progress))驱动进度条伸缩(后者性能更好) - 进度条容器需设
position: fixed; top: 0; left: 0; height: 3px; z-index: 9999;,且内部条元素加overflow: hidden防溢出
容易踩的坑:别误用 view() 时间线模拟进度
有人尝试给 或首屏元素加 animation-timeline: view() 并配 animation-range: entry 0% cover 100%,以为这样就能“从进入视口播到离开视口”。但实际效果是:
-
view()的 0% 是元素**上边缘刚进入视口顶部**,100% 是**下边缘刚离开视口底部**,和文档整体滚动进度无关 - 如果页面很长,首屏元素早就滚走了,后续内容根本不会触发该动画
- 它无法响应用户快速滚动、跳转锚点等行为,进度条会卡死或跳变
- Chrome DevTools 的 Animations 面板里能看到该动画被标记为 “inactive” 或 “skipped”,因为浏览器认为它已超出视图生命周期
真正要让进度条跟住每一次像素级滚动,就得老老实实算 scrollTop。CSS 滚动驱动动画很酷,但它不是万能胶——它擅长的是“当某段内容进入视野时淡入”,而不是“我此刻滚到了全文第 67.3% 的位置”。这个分寸,很容易混淆。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











