scroll-timeline 是将滚动进度映射为0%→100%时间轴的CSS机制,不直接控制显隐;需配合opacity等可动画属性及@keyframes实现淡入效果,例如设animation-range: 60% 70%并在关键帧中定义opacity变化。

scroll-timeline 是什么,它能直接控制元素显隐吗?
scroll-timeline 本身不直接显示或隐藏元素,它只是把滚动进度映射成一个时间轴(0% → 100%),供 @keyframes 动画消费。真正控制显隐的,还是 opacity、visibility 或 transform 这类可动画属性。如果你期望“一滚到某位置就立刻显示”,得靠动画关键帧配合足够陡峭的过渡(比如 0%→99% 隐藏,100% 显示),而不是靠 JS 监听 scroll 事件手动切 display。
- 它依赖父容器设
overflow: auto(或scroll)且有明确高度,否则滚动上下文无法建立 - 必须用
scroll-timeline-name命名时间轴,再在动画里用animation-timeline引用,名字要严格匹配 - 目前仅 Chromium 115+ 和 Safari 17.4+ 原生支持,Firefox 仍需前缀
-moz-scroll-timeline(且实现不完整)
怎么写一个滚动到父容器 60% 位置时淡入的元素?
核心是定义滚动时间轴 + 关键帧动画 + 绑定。假设父容器是 .scroller,目标元素是 .target:
.scroller {
height: 400px;
overflow-y: auto;
scroll-timeline-name: --vertical-scroller;
}
<p>.target {
animation: fade-in 1s linear;
animation-timeline: --vertical-scroller;
animation-range: 60% 70%; /<em> 滚动从 60% 到 70% 期间播放动画 </em>/
}</p><p>@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}-
animation-range是关键:它不是“触发点”,而是“动画生效的滚动区间”。设60% 70%意味着当滚动进度进入该范围时,动画从 0% → 100% 执行;若想“刚好在 60% 时完成淡入”,可设59% 60%并配animation-duration: 0.01s,但视觉上更稳的做法是用from { opacity: 0 } to { opacity: 1 }+ 合理区间 - 不要漏掉
scroll-timeline-name的双横线前缀(--name),这是 CSS 自定义标识符的强制语法 - 若父容器没有固定高度或
overflow,scroll-timeline会静默失效,DevTools 的 Animations 面板里也看不到时间轴
为什么元素没反应?常见断点检查清单
滚动时间轴失效往往卡在底层条件,而不是动画写法:
- 父容器是否设置了
height且内容高度 > 容器高度?scroll-timeline需真实滚动距离,overflow: hidden或内容未溢出都会导致时间轴长度为 0 - 是否用了
scroll-timeline-axis: block(默认值)?如果父容器是横向滚动,必须显式设scroll-timeline-axis: inline,否则时间轴始终按垂直方向计算 - 检查浏览器支持:运行
if ('scrollTimeline' in document) {...}或在 DevTools 的 Elements 面板里看animation-timeline是否被划掉(strikethrough) -
animation-range的起止值不能超过0% / 100%,也不能写成小数(如0.6),必须带百分号 - 元素本身不能有
animation-fill-mode: none(默认是both),否则动画结束后样式会回退
兼容性 fallback 怎么做才不冗余?
别写两套逻辑(CSS 时间轴 + JS 滚动监听)。优先用 @supports 隔离原生能力:
立即学习“前端免费学习笔记(深入)”;
.target {
opacity: 0;
transition: opacity 0.3s;
}
<p>@supports (animation-timeline: --t) {
.target {
opacity: 0;
animation: fade-in 0.3s linear forwards;
animation-timeline: --vertical-scroller;
animation-range: 55% 65%;
}
}</p><p>/<em> JS fallback 只在不支持时加载 </em>/
if (!CSS.supports('animation-timeline', '--t')) {
const observer = new IntersectionObserver(...);
observer.observe(document.querySelector('.target'));
}-
@supports (animation-timeline: --t)是最准的检测方式,比查 UA 或版本号可靠 - 不要在同一元素上混用 CSS 时间轴和 JS
IntersectionObserver,容易冲突;用@supports切换整套行为更干净 - 注意:Safari 17.4 虽支持
scroll-timeline,但对animation-range的解析有偏差(比如0% 0%可能不触发),测试时务必用真实滚动,而非 DevTools 的 timeline 拖拽模拟
滚动位置驱动显隐这事,scroll-timeline 把声明式逻辑往前推了一大步,但它的“时间轴”本质意味着你得习惯用区间思维,而不是精确触发点——这点和 JS 的 scrollY 判断很不同,容易一开始写反范围。


















