scroll-driven animations 的基础声明是否生效取决于浏览器支持与正确配置:Chrome 115+/Edge 115+ 原生支持,Firefox 需手动启用 flag,Safari 17.4+ 仅支持垂直滚动;须用 @supports 检测、确保 source 可滚动且 animation-timeline 名称匹配。

scroll-driven animations 的基础声明是否生效?
CSS 滚动驱动动画依赖 @keyframes 和 @scroll-timeline 两个核心机制,但浏览器支持不等于默认可用。Chrome 115+、Edge 115+ 原生支持,Firefox 仍需 layout.css.scroll-driven-animations.enabled 手动开启(about:config),Safari 17.4+ 才开始支持 scroll-timeline,且仅限垂直滚动。
确认是否启用的方法很简单:在 DevTools 的 Styles 面板里给元素加 animation-timeline: --progress;,如果该属性被划掉或不生效,大概率是浏览器未启用或语法有误。
实操建议:
- 始终用
@supports (animation-timeline: --t) {}包裹 scroll-driven 动画相关样式,避免降级失败 - 不要省略
--scroll-timeline-name的自定义标识符,例如--progress,它必须和@scroll-timeline中的名称完全一致(区分大小写) - 滚动容器必须有明确的滚动上下文:要么是
body,要么是设置了overflow-y: scroll且height或max-height有限的元素
如何让进度条宽度随页面滚动线性变化?
滚动进度条本质是把「滚动距离 / 可滚动高度」映射为 width 或 transform: scaleX()。关键不是靠 JS 监听 scroll,而是用 @scroll-timeline 定义滚动范围,再用 animation-timeline 绑定。
立即学习“前端免费学习笔记(深入)”;
@scroll-timeline progress-tl {
source: selector(#scroller);
orientation: vertical;
start: 0;
end: 100%;
}注意几个易错点:
-
source必须指向一个真实存在的、可滚动的容器;若想绑定到body,得写source: selector(html)或source: auto(后者仅对根滚动生效) -
start和end是滚动位置锚点,单位是%或px,但推荐用%保证响应式兼容性 -
orientation必须显式声明,即使只做垂直滚动——遗漏会导致 timeline 不触发
然后定义动画并绑定:
@keyframes fill-progress {
from { width: 0%; }
to { width: 100%; }
}
<p>.progress-bar {
animation: fill-progress 1s linear;
animation-timeline: --progress;
/<em> 注意:这里的名字必须和 @scroll-timeline 名称一致 </em>/
}为什么进度条不动或跳变?常见绑定错误
最常踩的坑是「滚动源和动画目标不在同一滚动上下文」。比如你给 .progress-bar 设置了 animation-timeline: --progress,但 @scroll-timeline --progress 的 source 指向的是某个 .content 区域,而实际滚动的是 body——这时 timeline 根本不会更新。
另一个隐蔽问题是:animation-fill-mode 缺失。如果不设 animation-fill-mode: forwards,滚动到底部后进度条会瞬间回退到 0%。
调试建议:
- 在 DevTools 的 Animations 面板中查看 timeline 是否在滚动时「实时更新 current time」,若始终为 0 或 NaN,说明 source 未命中或不可滚动
- 用
getComputedStyle(el).animationTimeline在控制台检查 timeline 是否正确解析(返回scroll()对象表示成功) - 避免在
position: fixed元素上直接使用 scroll-driven animation——它的布局脱离文档流,但 timeline 仍按文档流坐标计算,容易错位
需要兼容旧浏览器时怎么降级?
scroll-driven animations 目前无法优雅 polyfill,JS 模拟是唯一可行路径。但不必重写整套逻辑:只需检测支持性, fallback 到 IntersectionObserver + requestAnimationFrame 计算滚动比即可。
if (!CSS.supports('animation-timeline', 'some-name')) {
const bar = document.querySelector('.progress-bar');
const scroller = document.scrollingElement || document.documentElement;
<p>const update = () => {
const h = scroller.scrollHeight - scroller.clientHeight;
const p = h ? Math.min(1, scroller.scrollTop / h) : 0;
bar.style.width = <code>${p * 100}%</code>;
};</p><p>scroller.addEventListener('scroll', update, { passive: true });
update();
}重点在于:不要试图用 scroll 事件高频更新(尤其在 iOS 上),务必加 { passive: true };同时首次执行 update() 补全初始状态,否则首屏可能显示 0%
滚动进度条看似简单,但真正卡住人的往往不是写法,而是 timeline 的 source 是否真实可滚动、是否被 overflow:hidden 截断、以及 Safari 对 auto source 的处理差异——这些细节不验证,光抄代码永远动不了。


















