Scroll-driven Animations不适合高性能滚动动画,因其易触发强制同步布局;应优先使用IntersectionObserver+transform方案,仅在固定容器、纯transform/opacity动效等极简场景下谨慎使用scroll-timeline。
Scroll-driven Animations 目前不能用于高性能滚动动画——它在 Chrome 115+/Safari 17.4+ 中可用,但极易触发强制同步布局,反而比 IntersectionObserver + requestAnimationFrame 更卡。
scroll-timeline 绑定到 body 或 html 为什么一定崩
浏览器无法缓存
或
的 layout 信息:它们的尺寸随内容动态变化,每次滚动帧都得重新测量、重排。尤其在 SPA 或富文本页面中,
可能因图片加载、字体回流而跳变,导致 timeline 进度计算反复失准,强制触发同步 layout。
常见错误写法:
正确做法是限定一个固定高度容器(如
或
),且该容器不参与文档流(
即可,无需绝对定位)。
立即学习
“
前端免费学习笔记(深入)
”;
哪些属性能安全绑定 scroll-timeline
只有不触发布局、不触发 paint 的 CSS 属性才适合纯 CSS 滚动驱动:
(
/
/
)——走合成层,安全
——不重排不重绘,仅合成器混合
(部分,如
、
)——需 GPU 支持,慎用高斯模糊
以下属性绝对禁止:
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
、
、
、
—— 触发 layout
、
—— 触发 paint,非合成优化路径
、
—— 引发文本重排重绘链
IntersectionObserver + transform 才是真高性能方案
当你要响应“进入/离开视口”这类粗粒度时机,或需要精确控制动效节奏(比如滚动 200px 后才开始 fade-in),
是唯一可靠选择。
关键实操点:
监听时设
,避免高频回调;只关心“是否可见”,不关心具体像素位置
动效全用
+
,目标元素加
或
提升图层
缓存
结果,不要在滚动回调里重复调用——它会强制同步 layout
若需滚动距离驱动(如视差位移),用
节流读取
,再注入 CSS 变量:
CSS 中写:
—— 乘法比除法更稳,避免 NaN 或负无穷
scroll-timeline 唯一能用的场景
它只适用于「静态、预知、零 JS」的极简动效,且满足三个硬条件:
滚动容器高度固定(如
)
目标元素脱离文档流(
或父级有
隔离)
动画全程只改
和
,且不依赖 DOM 尺寸计算
典型可用案例:
顶部 banner 图片从透明到完全显示(
)
固定高度轮播区里,卡片水平平移入场(
)
纯 CSS 分段背景色切换(
在
中线性过渡)
一旦你写了
、绑了
、或者动画里用了
,性能就已失控——这不是配置问题,是机制限制。
bodyhtmldocument.body.scrollHeight@scroll-timeline --tl {
source: selector(body); /* ❌ 不稳定滚动源 */
start: 0%;
end: 100%;
}height: 100vhmax-height: 800pxposition: relativetransformtranslateXtranslateYscaleopacityfilterblur()grayscale()widthheightlefttopbackground-positionbox-shadowfont-sizeline-heightIntersectionObserverthreshold: [0, 0.1, 0.5, 1]transformopacitywill-change: transformtransform: translateZ(0)getBoundingClientRect()requestAnimationFramewindow.scrollYel.style.setProperty('--scroll-y', scrollY + 'px')transform: translateY(calc(var(--scroll-y) * 0.3));section { height: 100vh; }position: absolutetransformtransformopacity@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }translateX(100%) → translateX(0)background-color@keyframesselector(#trigger)bodymargin-top