display是离散属性,无中间状态,transition对其无效;应改用opacity+transform组合实现平滑滚动动画,并通过requestAnimationFrame节流滚动监听。

为什么直接用 display + transition 会失效
因为 display 是离散属性,没有中间状态,浏览器无法插值计算。你写 transition: display 0.3s 完全没用——它要么是 none,要么是 block,不会“慢慢出现”。实际滚动中看到的“闪现”或“突兀显示”,基本都源于这个误用。
opacity + transform 才是滚动触发动画的黄金组合
要让元素随滚动位置平滑入场/退场,必须同时控制透明度和位移。只靠 opacity 是平面淡入,加 transform: translateY() 或 translateX() 才有空间感和方向性,接近原生 App 的动效逻辑。
-
opacity负责视觉显隐(0 → 1) -
transform: translateY(20px)让元素从下方“滑上来”,初始设为opacity: 0; transform: translateY(20px) - 过渡必须写在基础类里,不能只写在触发类中:
transition: opacity 0.4s ease, transform 0.4s ease - 避免用
top/left做位移——它们会触发重排,transform走合成层,更流畅
JavaScript 监听滚动时的三个关键点
滚动动画卡顿、错位、反复触发,往往不是 CSS 写错了,而是 JS 绑定方式有问题。
- 必须节流:用
requestAnimationFrame或setTimeout包一层,避免每像素都触发重计算 - 判断逻辑别写成
if (scrollTop > 500)这种硬阈值,改用getBoundingClientRect().top 更可靠(考虑视口比例) - 切换 class 别用
element.className = 'show'—— 会清空所有已有 class;改用element.classList.add('is-visible')和element.classList.remove('is-visible')
移动端 Safari 的 opacity 动画掉帧怎么破
iOS 15.4 之前,纯 opacity 配合 position: fixed 或 sticky 元素,在快速滚动时容易掉帧。这不是 bug,是渲染管线限制。
立即学习“前端免费学习笔记(深入)”;
- 加
will-change: opacity提前告诉浏览器该属性要变(但别滥用,只加在真正需要的元素上) - 对 sticky 元素,补一句
transform: translateZ(0)强制提升为独立图层 - 慎用
visibility: hidden替代opacity: 0:它虽能禁交互,但会导致滚动定位偏移(尤其配合position: sticky时) - 真要兼顾性能与语义,用
opacity: 0; pointer-events: none比visibility: hidden更稳
滚动触发动画最易被忽略的,其实是「入场判定时机」——很多人等元素完全进入视口才开始动画,结果用户已经划过去了。真正顺滑的体验,是它在离视口顶部还有 20% 时就开始缓入,而不是等“刚好露头”才动。


















