animation-timeline: scroll(root) 常静默失效,因滚动上下文被 overflow: hidden、overscroll-behavior 或 position: fixed 等隔离;需确保 document.scrollingElement 具备真实滚动能力。

直接用 animation-timeline: scroll(root) 大概率不生效——不是语法错,而是滚动上下文没成立。必须先确认浏览器真正在“滚动文档根”,而不是被 overflow: hidden、overscroll-behavior: none 或 position: fixed 隔离了滚动流。
为什么 animation-timeline: scroll() 经常静默失败
它不报错,也不警告,只是完全不触发动画。根本原因是:scroll() 默认绑定到 root(即 document.scrollingElement),但现代页面中这个元素往往没有真实滚动能力。
-
html或body上写了height: 100vh; overflow: hidden→ 滚动被禁用,scrollHeight === clientHeight - 外层容器用了
overscroll-behavior: contain→ 滚动事件传播被截断 - 目标元素被
position: fixed或transform隔离出滚动坐标系 →getBoundingClientRect().top不随滚动变化 - 写了
animation-timeline: scroll(body)→ Chrome 直接忽略,body不是合法 scroller
@scroll-timeline 定义时 start/end 该用 px 还是 %
必须用 px 或 vh,不要用 %。因为 @scroll-timeline 的 start 和 end 是相对于滚动容器内容高度(scrollHeight)的绝对偏移,不是百分比进度。
-
start: 0px; end: 100vh:可靠,锚定视口高度,适合首屏触发 -
start: 0px; end: 500px:适合内容高度稳定、有明确滚动区间的容器 -
start: 0%; end: 100%:规范不支持,多数浏览器静默忽略整条规则 - 动态内容(如懒加载图片)撑开高度后,
%值会因基准变动导致动画错位
如何让多个元素同步响应同一滚动进度
不能靠各自写 animation-timeline: scroll(root) —— 它们会按自身 DOM 位置分别计算起止点,不是统一按文档总高算百分比。
立即学习“前端免费学习笔记(深入)”;
- 必须显式定义命名时间线:
@scroll-timeline --global-scroll { source: selector(html); orientation: vertical; start: 0px; end: 100vh; } -
source: selector(html)比selector(body)更可靠,Chrome 认可html为有效 scroller - 所有元素统一绑定:
animation-timeline: --global-scroll - 若需不同区间触发,用
animation-range控制,例如:animation-range: 0% 33%和animation-range: 33% 66%
animation: name auto 中的 auto 为什么不能省
这是滚动驱动动画的开关。没有 auto,动画就退化成普通时间驱动动画,和滚动完全脱节。
-
animation: fade-in 2s→ 强行 2 秒播完,滚动快慢不影响 -
animation: fade-in auto→ 滚动 10%,动画就走到 10% 关键帧;滚动暂停,动画暂停 - Chrome 115+ 原生支持;Firefox 需开启
layout.css.scroll-driven-animations.enabled - 不支持时,
animation-timeline值被忽略,但animation仍按 document timeline 播放 → 动画会从页面加载就开始跑,必须做兼容性兜底
最易被忽略的一点:原生 CSS 滚动驱动动画无法实现真正的“全局滚动进度条”(比如顶部固定、宽度随 scrollTop/(scrollHeight-clientHeight) 实时变化的横条)。它不提供可读取的滚动百分比值,scroll() 只能映射播放进度,不能反向控制 width 或 scaleX。这种场景必须用 JS 计算并同步 CSS 变量。


















