← CSS Animation · 能力速览 / 性能与取舍:该用 CSS 还是 JS? 待审核 18 / 22
性能 · CSS vs JS · 主线程

性能与取舍:该用 CSS 还是 JS?

常听说「CSS 动画比 JS 快」。Josh Comeau 指出:差别不在计算性能、也不在语言,而在线程——JS 动画(requestAnimationFrame)和应用里的一切逻辑共用主线程,主线程一阻塞就掉帧;而 transform/opacity 这类动画能交给合成线程(compositor)独立运行,主线程再忙也保持流畅。(来源:Josh Comeau

1 · 主线程这道分界(关键 demo)

三条轨道同样来回滑:绿用 CSS transform(可合成)、用 CSS margin-left(每帧要重排,得走主线程)、用 JS requestAnimationFrame(主线程)。点「阻塞主线程」跑一段同步死循环——看谁照样在动,谁卡住

绿块的 transform 动画跑在合成线程,主线程被死循环占满也不影响它;红块虽然也是 CSS,但 margin-left 每帧都要重新布局(layout),只能在主线程做,于是和 JS 的紫块一起被卡住。结论:决定流畅度的首先是「这条属性能不能合成」,其次才是 CSS 还是 JS。

2 · 选对属性 > 选对语言

动画尽量只改合成友好的属性,避免每帧触发 layout / paint:

属性类别 代表属性 代价
合成友好 (compositor) transform(translate / scale / rotate)、opacity 不触发 layout / paint,可下合成线程;filter 多数情况也较廉价
触发 layout (reflow) width / height / top / left / margin / padding / font-size 改它们每帧都要重排,开销大
触发 paint (重绘) background / color / box-shadow / border-radius 不重排但要重绘

想「移动」元素优先 transform: translate() 而非 left / margin;will-change: transform 可提示浏览器提前提层(别滥用)。

3 · JS 也能「下主线程」:WAAPI 与库

JS 动画并非注定卡:Web Animations APIelement.animate()(见动画事件那页)创建的动画,浏览器同样能交给合成线程,从而摆脱主线程。

底层 线程 说明
Motion(原 Framer Motion) WAAPI 能下合成线程 适合 React / 复杂交互
GSAP 自有引擎 主要主线程 时间线 / SVG / 物理很强,但被打断时不保持时间同步
只是「包了一层 CSS」的库 没带来 CSS 做不到的新能力,却增加 bundle 体积,收益为负

取舍建议:其一,普通过渡 / 关键帧——优先纯 CSS;其二,需要 CSS 做不到的能力(SVG morph、可中断的手势 / 物理、复杂编排)才引入 JS 库,并优先选走 WAAPI、能下放合成线程的;其三,无论 CSS 还是 JS,动画都尽量只动 transform/opacity