<p>CSS 的 animation-timeline: scroll() 无法实现全局滚动进度条,因其不提供文档级滚动百分比;必须用 JS 计算 scrollTop / (scrollHeight - clientHeight) 并注入 CSS 变量配合 @property 实现平滑进度条。</p>

animation-timeline: scroll() 不能直接实现页面顶部的全局滚动进度条。这是个常见误解——它看起来能“绑定滚动”,但实际无法读取或输出文档级滚动百分比,更不能驱动 width 或 transform: scaleX() 这类依赖数值的属性。
为什么 scroll() 绑定到 body 或 html 会失效
浏览器对根滚动容器(document.scrollingElement)的 scroll() 解析存在硬性限制:
- scroll(root) 在 Chrome 115+ 中可识别,但仅用于触发动画播放,不提供可映射的 0%→100% 数值
- 动画起止点由元素在 DOM 中的位置决定,不是按整页高度统一计算
- 若未显式设置 scroll-timeline-name + @scroll-timeline 规则,scroll() 会被静默忽略
- Firefox 当前仍需手动开启 layout.css.scroll-driven-animations.enabled 实验标志
animation: name auto 是必须写的,不是可选语法糖
漏掉 auto 就等于放弃滚动驱动:
- animation: progress-bar 2s linear → 按固定 2 秒播完,与滚动完全脱节
- animation: progress-bar auto linear → 浏览器将滚动位移映射为动画进度 0%→100%,帧率与滚动位置一一对应
- 即使写了 animation-duration: 1ms,只要没写 auto,Chrome 就会降级为 document timeline,从页面加载开始播放
- auto 必须出现在 animation 简写中,不能只写在 animation-duration 单独属性里
真正能用 CSS 做出顶部进度条的唯一可行路径
必须绕过 scroll() 的数值盲区,用 JS 计算并注入 CSS 变量:
- 监听 scroll 事件,实时计算 scrollTop / (scrollHeight - clientHeight)
- 写入 document.documentElement.style.setProperty('--scroll-progress', value)
- 进度条样式用 width: calc(var(--scroll-progress) * 100%) 或 transform: scaleX(var(--scroll-progress))
- 配合 @property 声明类型(如 @property --scroll-progress { syntax: '<number>'; inherits: false; initial-value: 0; }</number>),才能让 scaleX() 平滑过渡
- 不声明 @property 时,scaleX() 会跳变,因为 CSS 默认不认为自定义变量可动画
最容易被忽略的兼容性断点
没有 animation-timeline 支持时,整条规则链会静默失效:
- scroll() 值被忽略 → animation-timeline 回退到默认 document timeline
- 动画从页面加载就开始播,和滚动无关
- 你不会看到任何报错,只有“动画动了但不对劲”的困惑
- 所以必须加 JS 版本兜底,且不能只靠 @supports (animation-timeline: scroll()) 判断——该特性检测在旧版 Safari 和部分安卓 WebView 中不可靠


















