与原生对照:浏览器自带了什么,为何仍手写引擎
浏览器原生提供三套动画能力:WAAPI(element.animate())做补间、
View Transitions(document.startViewTransition())做 DOM 状态切换的自动过渡、
scroll-driven animation(animation-timeline: scroll()/view())把动画声明式绑到滚动。
它们各有清晰的适用边界。本页用同一类效果分别对照演示,并解释这套手写引擎(@vega/anim)在
可 seek、可确定性测试、跨属性统一、不依赖浏览器实现这几点上补齐了什么。对不支持的 API 做 feature-detect,
不支持时降级为提示。
WAAPI · element.animate()
原生补间,返回 Animation 对象,可 pause / reverse / 写 currentTime。
@vega/anim · 手写引擎
同样的接口面,但游标 / 采样在 JS 内,可被手动驱动器确定性测试。
View Transitions · 列表重排
- item · alpha
- item · bravo
- item · charlie
- item · delta
本浏览器不支持 View Transitions API,已降级为直接重排(无过渡)。
把 DOM 改动包进 startViewTransition(),浏览器自动对前后快照做 morph。
scroll-driven · 滚动绑定(无 JS)
向下滚动这个容器,橙色进度条由 animation-timeline 直接驱动,JS 全程未参与。
本浏览器不支持 scroll-driven animation(animation-timeline: scroll()),进度条不会随滚动变化。
| 能力 | WAAPI | View Transitions | scroll-driven | @vega/anim |
|---|---|---|---|---|
| seek / scrub | 可 | 不可 | 由滚动隐式驱动 | 可 |
| reverse | 可 | 不可 | 由滚动方向决定 | 可 |
| 确定性测试 | 依赖真实时钟 | 依赖渲染快照 | 依赖滚动环境 | 可(手动驱动器) |
| 跨属性统一(数字 / 颜色 / 弹簧) | 逐属性各异 | 仅 crossfade / transform | CSS 可动属性 | 统一插值管线 |
| 自定义弹簧 / 衰减 | 无 | 无 | 无 | spring / decay |
| 浏览器支持 | 广泛 | 较新(Chromium 先行) | 较新(Chromium 先行) | 仅需 JS 运行时 |
currentTime
都很好,但跨属性的语义并不统一,且没有弹簧 / 衰减这类物理模型;其二 View Transitions 解决的是
「DOM 从状态 A 切到状态 B 时的自动过渡」,适合路由切换、列表增删,但它不是一个可 seek / 可反向的播放器;
其三 scroll-driven 用声明式 CSS 把时间轴绑到滚动,零 JS,但时间轴只能来自滚动。手写引擎不与它们竞争「最省力」,
而是补齐可 seek、可确定性测试、跨属性统一插值、不依赖浏览器实现这组属性——把动画当作一条
时间 → 值 的纯函数管线,游标由可替换的驱动器推动,
因此既能接 rAF 实时跑,也能用手动驱动器在测试里逐帧推进。
实践中三者常并用:能用 scroll-driven 声明式表达的就别写 JS;页面 / 列表的状态切换交给 View Transitions; 而需要被精确 scrub、需要弹簧 / 惯性、需要在单元测试里断言每一帧的场景,用手写引擎。下面对照 WAAPI 与 View Transitions 的最小调用。
手写引擎之所以能像 WAAPI 那样 pause / reverse / seek,根因见播放控制:为什么动画可以回退 (游标 + speed 的纯函数管线);把滚动当作驱动游标的输入、做成可 scrub 的滚动动画,见 交互驱动:手势与滚动。