flip动画是基于浏览器渲染机制的四步手动调度策略,即first(读初态)、last(改dom)、invert(requestanimationframe中反向计算并设transform)、play(移除transform触发过渡)。

FLIP动画不是CSS属性,是四步操作流程
很多人一搜“FLIP动画”就去翻transition或@keyframes文档,结果白忙——FLIP根本不是CSS语法,而是基于浏览器渲染机制的一套手动调度策略。它不依赖新API,但必须严格按First → Last → Invert → Play四步执行,漏一步动画就断在视觉突变上。
关键在于:浏览器只对transform、opacity这类合成属性做60fps动画;而top、height、display等触发重排的属性无法平滑过渡。FLIP就是把“布局变化”强行映射到transform上。
-
First:用getBoundingClientRect()读取元素初始位置(必须在此刻读,否则后续DOM变更会让值失效) -
Last:直接修改DOM(比如插入新项、切换class、改变flex顺序),让元素到达终态 -
Invert:立即用requestAnimationFrame读取终态位置,再反向计算位移/缩放,通过style.transform把元素“拽回”初始视觉位置 -
Play:移除transform(或设为none),靠transition自动播放到终态
列表增删为什么不能直接用transition: height
因为height: 0 → auto无法过渡,display: none会立刻从渲染树移除,浏览器根本没机会采样中间帧。你看到的“闪现”或“瞬移”,本质是强制同步重排打断了动画管线。
FLIP在这里的解法很直接:不碰height和display,而是给每个<li>加一层transform: scaleY(0)占位,增删时只动transform和opacity。
- 新增项:先
opacity: 0; transform: scaleY(0)插入DOM,再requestAnimationFrame后移除这些样式 - 删除项:先记录
getBoundingClientRect(),再加transform: scaleY(0) opacity: 0,动画结束后才真正remove() - 务必给父容器加
overflow: hidden,否则scaleY(0)缩放时内容可能溢出
requestAnimationFrame在哪一步调用最安全
只在Invert这一步调用requestAnimationFrame,其他三步都得同步执行。常见错误是把Last(DOM变更)也包进requestAnimationFrame回调里,导致读取的“终态”其实是旧值。
正确节奏是:
- 同步执行
First(读初态) - 同步执行
Last(改DOM,让布局重算) - 立即调用
requestAnimationFrame(() => { /* Invert + Play */ }) - 在回调里读终态、算差值、设
transform、再移除transform
如果用setTimeout(..., 0)代替requestAnimationFrame,动画可能掉帧,尤其在低端设备上。
FLIP动画容易被忽略的硬件加速细节
哪怕transform写对了,没触发GPU合成层,动画照样卡顿。必须确保参与FLIP的元素满足以下至少一条:
- 有
will-change: transform(仅用于明确动画元素,别滥用) - 父容器设置了
transform: translateZ(0)或perspective: 1px - 元素本身有
backface-visibility: hidden(防文字模糊)
特别注意:如果列表项用了filter: drop-shadow(),会强制创建独立层,反而增加内存开销,此时应改用box-shadow替代。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











