intersection observer 是唯一可靠方案,因 scroll-timeline 仅支持动画时间轴映射,无法处理 display 切换等离散状态,且存在兼容性差、易被样式拦截等问题。

滚动驱动显示/隐藏目前只能靠 Intersection Observer API 实现,CSS 的 scroll-timeline 不支持显隐控制,只管动画时间轴。
为什么不能用 scroll-timeline 做显示隐藏
CSS 的 scroll-timeline 本质是把滚动位置映射为动画时间进度(0% → 100%),它必须配合 @keyframes 和 animation 使用。但显隐是离散状态切换(display: none ↔ block / opacity: 0 ↔ 1),不是连续插值过程——opacity 可以靠关键帧硬切,display 则完全无法参与 CSS 动画(浏览器会忽略)。所以即使写了 animation: fade-in 1s linear forwards,一旦涉及 display,实际效果就不可控或失效。
-
visibility和opacity可被动画,但它们不释放文档流,可能影响布局或触发意外交互 -
scroll-timeline在 Safari 中完全不解析,Firefox 仅实验性支持且需手动开启标志,Chrome/Edge 是唯一稳定环境 - 哪怕在 Chrome 里,
animation-timeline: scroll()被父容器 overflow: hidden 或 position: fixed 拦截时,也会静默失效(DevTools 的 Computed 面板里看不到该属性)
Intersection Observer 是唯一可靠方案
它监听元素是否进入/离开视口,触发回调函数,由 JS 显式控制 class、style 或属性。兼容性好(IE11+ 需 polyfill),语义清晰,无渲染副作用。
- 初始化时传入
{ root: null, threshold: 0.1 }:表示目标元素 10% 进入视口即触发 - 回调中用
entries[i].isIntersecting判断是否可见,再操作element.classList.toggle('visible', isIntersecting) - 避免在回调里直接改
style.display,优先用 CSS class 控制,利于复用过渡动画 - 记得调用
observer.unobserve(element)防止内存泄漏(比如只显示一次后不再监听)
常见踩坑点:伪“滚动驱动”误判
很多人用 window.scrollY + element.offsetTop 手动计算显隐,这看似简单,实则问题密集:
- 没考虑
getBoundingClientRect().top相对于视口的实时位置,而是依赖静态offsetTop,一旦页面有 sticky header、动态插入内容或 CSS transform,立刻错位 - 没做节流,
scroll事件高频触发导致重复执行、卡顿甚至样式抖动 - 没处理
resize事件,窗口缩放后阈值失效 - 移动端 touchmove 滚动下,
scroll事件可能延迟触发或丢失,导致显隐不同步
一个最小可用的 Intersection Observer 示例
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('in-view');
// 可选:只触发一次
observer.unobserve(entry.target);
}
});
}, { threshold: 0.05 });
document.querySelectorAll('.js-trigger').forEach(el => observer.observe(el));
CSS 配合:.js-trigger { opacity: 0; transition: opacity 0.4s ease; } .js-trigger.in-view { opacity: 1; }。注意:不要给 .js-trigger 加 display: none 初始态,否则它根本不会被 Observer 检测到。
真正难的不是写几行代码,而是判断“什么时候该显、什么时候该隐”——比如是否要等用户停顿后再触发,是否要排除懒加载图片占位符的干扰,是否要适配深色模式下的 contrast 检测。这些细节不在 API 层面,而在业务逻辑里。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











