FLIP 布局动画

FLIP

FLIP Flip 动画 布局过渡 Layout Animation First Last Invert Play 共享元素过渡

先记录元素当前位置,直接修改 DOM 布局,再从旧状态平滑过渡到新状态;GSAP 的 Flip 插件把这套流程封装成两步调用。

又称:Flip 动画 · 布局过渡 · Layout Animation · First Last Invert Play · 共享元素过渡

  • GSAP
  • CSS
  • Claude / Cursor
1
2
3
4
5
6
Flip.getState() → 改变布局 → Flip.from(state)

Prompt 片段

  • Claude / Cursor
    用 GSAP Flip 实现网格与列表视图切换:点击按钮前 Flip.getState(items),切换容器的 is-list 类,再 Flip.from(state, { duration: 0.9, ease: 'expo.inOut', stagger: 0.03, absolute: true })。
  • Claude / CursoronEnter / onLeave 需要在 getState 时就包含所有可能出现的元素
    筛选商品卡片时用 Flip 做过渡:保留下来的卡片平滑移动到新位置,新出现的用 onEnter 淡入,被筛掉的用 onLeave 淡出。
  • Claude / Cursor
    点击缩略图时把它移动到详情容器里(appendChild),用 Flip 让图片从缩略图位置放大到详情位置,开启 scale: true 以提升性能。

是什么

FLIP 是 First、Last、Invert、Play 四个词的缩写,是一种布局动画技巧:先记录元素的初始位置(First),直接把 DOM 改成最终布局(Last),计算两者差值并用 transform 把元素「拉回」原处(Invert),最后移除这个偏移并播放动画(Play)。这样就能在不逐帧改变布局的前提下,让任何布局变化都平滑过渡。

GSAP 的 Flip 插件随 gsap 包免费提供,从 gsap/Flip 导入。它把这套流程简化为:Flip.getState() 记录状态,你随意修改 DOM,然后 Flip.from(state) 播放过渡。上方演示中,6 个色块在三列网格和单列列表之间切换,同时打乱顺序,每个色块都从原位置平滑移动并缩放到新位置。

核心参数

参数 含义
duration / ease 过渡的时长与缓动
absolute 过渡期间把元素设为绝对定位,避免 Grid、Flex 布局互相挤压
stagger 让元素依次开始归位
nested 嵌套元素同时变化时,避免位移被重复计算
scale 用 scaleX/scaleY 代替 width/height 过渡,性能更好
onEnter / onLeave 处理新出现和被移除的元素

代码示例

import { gsap } from 'gsap';
import { Flip } from 'gsap/Flip';

gsap.registerPlugin(Flip);

const grid = document.querySelector('.grid');
const items = gsap.utils.toArray('.item');

document.querySelector('.toggle').addEventListener('click', () => {
  const state = Flip.getState(items); // 1. 记录当前位置与尺寸

  grid.classList.toggle('is-list'); // 2. 直接修改布局
  gsap.utils.shuffle([...items]).forEach((el) => grid.appendChild(el));

  Flip.from(state, { // 3. 从旧状态过渡到新状态
    duration: 0.9,
    ease: 'expo.inOut',
    stagger: 0.03,
    absolute: true,
  });
});

什么时候用

  • 网格与列表视图切换、卡片排序和筛选。
  • 缩略图展开为详情、元素在不同容器间移动。
  • 任何「布局由 CSS 决定、只想让变化过程更顺滑」的场景。

常见误区

  • 在修改 DOM 之后才调用 Flip.getState():记录到的已经是最终状态,动画不会发生。
  • 在 Grid 或 Flex 容器中不开 absolute:过渡期间元素仍参与布局,会出现跳动。
  • 用它做纯装饰性的位移:如果起止位置都是已知数值,直接写补间更简单。
esc