mcpField
U
ui-animation

ui-animation

github.com/lukasstrickler设计与 UI453 次安装35 周前更新
代码仓库

关于 ui-animation

用于设计 UI 动画的工作流技能,提供时长、Motion 与 CSS/Tailwind 技术、无障碍和性能方面的指导,面向实现界面过渡、手势和布局变化的开发者。

主要功能

  1. 01按动画类型选择技术
  2. 02提供缓动与时长建议
  3. 03涵盖 Motion 手势与布局过渡
  4. 04考虑减少动态效果偏好
  5. 05检查性能与焦点行为
  6. 06提供可复用动画示例

适用场景

  1. 01为模态框和下拉菜单添加进出场效果
  2. 02为手势控件和布局变化添加动画
  3. 03为偏好减少动态效果的用户调整动画
  4. 04检查动画性能与焦点行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lukasstrickler/ai-dev-atelier --skill ui-animation

安装后在 Claude Code 中输入/ui-animation确认已加载。

附带文件references/recipes.md

详细介绍

UI 动画

恰到好处的 UI 动画,兼顾时机、无障碍性和性能。

快速入门

技术选择:

  • 简单过渡? → CSS/Tailwind(transition-*、animate-*)
  • 进入/退出时卸载? → Motion + AnimatePresence
  • 由手势驱动? → Motion 弹簧动画
  • 布局变化? → Motion layout 属性

默认流程: 从缓动决策树 → 时长指南 → 实现 → 添加无障碍支持 → 验证

核心原则

  1. 自然运动:模拟物理规律。避免线性缓动——没有任何东西会以恒定速度移动。
  2. 有明确目的:每个动画都必须传达意义。如果无法说明它的好处,就删掉它。
  3. 快速:UI 动画控制在 300ms 以内。悬停效果控制在 150ms 以内。超过 500ms 会显得迟缓。
  4. 可中断:由手势驱动的动画使用弹簧动画——它们能妥善处理动画中断。
  5. 无障碍:始终遵循 prefers-reduced-motion。这点不可妥协。

工作流

步骤 1:对动画类型进行分类
类型示例技术
微交互按钮按下、切换、复选框CSS/Tailwind
进入/退出模态框、提示消息、下拉菜单Motion + AnimatePresence
布局变化手风琴、重新排序、展开Motion layout 属性
共享元素标签指示器、卡片展开Motion layoutId
手势拖动、滑动、下拉刷新Motion 弹簧动画
步骤 2:选择时机
  1. 使用下方的缓动决策树选择曲线
  2. 使用时长指南选择时长
  3. 对于手势,使用弹簧动画配置
步骤 3:实现
  1. 在 references/recipes.md 中查看可直接复制粘贴的模式
  2. 应用步骤 2 中选择的时机
  3. 用 AnimatePresence 包裹卸载时需要播放动画的元素

从设计截图或模型图开始时,使用 ui_to_artifact。使用 ui_diff_check 对比预期 UI 与实现结果。

步骤 4:无障碍(必需)
  1. 使用 useReducedMotion() 或 motion-safe: 检查 prefers-reduced-motion
  2. 对减少动态效果的用户,将动画简化为仅改变不透明度
  3. 验证焦点时机(动画开始后再移动焦点)
步骤 5:验证
  • 退出动画会播放(而非立即卸载)
  • opacity: 0 的元素设置了 pointerEvents: none
  • 动画开始后再移动焦点,而非动画开始前
  • 仅对 transform 和 opacity 设置动画

缓动

决策树
What triggers the animation?
│
├─ User action (click, tap, open)?
│  └─ Use: ease-out (fast start, slow end = responsive)
│
├─ Element moving on-screen (tab switch, reorder)?
│  └─ Use: ease-in-out (accelerate then decelerate)
│
├─ Continuous/looping (spinner, marquee)?
│  └─ Use: linear (constant speed appropriate here)
│
├─ Gesture-based (drag, swipe, pull)?
│  └─ Use: Spring animation (physics-based, interruptible)
│
└─ Hover/focus effect?
   └─ Use: CSS ease, 150ms (subtle, immediate)
快速参考
用途CSSTailwind时长
模态框/抽屉进入cubic-bezier(0.32, 0.72, 0, 1)ease-out duration-200200ms
模态框/抽屉退出cubic-bezier(0.32, 0.72, 0, 1)ease-out duration-150150ms
屏幕内移动cubic-bezier(0.4, 0, 0.2, 1)ease-in-out duration-200200-300ms
悬停效果easeease duration-150150ms
按钮按下—active:scale-[0.97]即时
专业曲线
名称值使用场景
Vaul(顺滑)cubic-bezier(0.32, 0.72, 0, 1)抽屉、侧滑面板、模态框
强调cubic-bezier(0.2, 0, 0, 1)Material Design 3
灵敏cubic-bezier(0.25, 1, 0.5, 1)快速 UI 过渡

避免使用:内置的 ease-in——起步缓慢,感觉迟钝。

时长指南

类型时长说明
微反馈100-150ms按钮按下、切换、复选框
小型过渡150-250ms工具提示、图标形变
中型过渡200-300ms模态框、弹出框、下拉菜单
大型过渡300-400ms页面过渡、复杂布局
最大值<500ms例外情况:引导流程、数据可视化

关键规则:

  • 退出速度快于进入:进入 200ms → 退出 150ms
  • 悬停要快:少于 150ms
  • 高频操作要即时响应:键盘导航、滚动——少于 100ms 或不加动画

弹簧动画

基于时长(推荐)

更易与其他定时动画组合使用。使用 visualDuration(视觉上到达目标所需的时间)和 bounce(0 表示无弹跳,1 表示弹跳明显)。

感觉配置使用场景
干脆{ duration: 0.3, bounce: 0.15 }选项卡、按钮、快速反馈
标准{ duration: 0.4, bounce: 0.2 }模态框、菜单、常规 UI
柔和{ duration: 0.5, bounce: 0.25 }流畅、自然的动效
基于物理参数(旧版/高级)

在与物理库集成或需要精确控制弹簧动力学时使用。

感觉配置使用场景
干脆{ stiffness: 400, damping: 30 }高频交互
标准{ stiffness: 300, damping: 20 }Framer Handshake 惯例
柔和{ stiffness: 120, damping: 14 }react-motion 预设

注意:stiffness/damping/mass 会覆盖 duration/bounce。选择一种方案,不要混用。

布局动画

layout 属性

添加 layout,即可自动为位置/尺寸变化添加动画。对文本使用 layout="position"(防止变形)。

属性值效果使用场景
layout={true}为位置和尺寸变化添加动画灵活元素的默认设置
layout="position"仅为位移添加动画不应拉伸的文本/图标
layout="size"仅为尺寸变化添加动画固定位置的展开面板
共享元素过渡(layoutId)

具有匹配 layoutId 的元素在进入/退出时会彼此间过渡。

关键陷阱:重复的 layoutId 值会导致元素瞬间跳到页面另一处。请在不同上下文中使用唯一 ID,或将元素放入 <LayoutGroup id="..."> 中。

布局注意事项
  • 文本变形:对文本元素应用 layout="position"
  • 边框圆角:缩放时可能会扭曲——Motion 会自动修正,但请进行测试
  • SVG 元素:layout 对 <path> 无效——请使用手动变形

手势注意事项

问题解决方案
触摸滚动冲突dragPropagation={false}
元素弹回原位检查 dragConstraints 和 dragElastic
惯性感觉不对对精确 UI 使用 dragMomentum={false}
只能朝一个方向拖动dragElastic={{ top: 0, bottom: 0.5 }}

滑动关闭:同时检查距离和速度——用户期望快速滑动也能生效。

无障碍

prefers-reduced-motion(必需)
import { useReducedMotion } from "motion/react"

const shouldReduce = useReducedMotion()
const variants = shouldReduce 
  ? { opacity: 1 }                    // Fade only
  : { opacity: 1, scale: 1, y: 0 }    // Full animation

Tailwind:motion-safe:animate-pulse/motion-reduce:transition-none

最佳实践:不要禁用动画,而是简化动画。移除空间位移,保留透明度变化。

焦点管理
  • 在动画开始后移动焦点:requestAnimationFrame(() => ref.focus())
  • 关闭时将焦点还原到触发元素
  • 不要在 aria-live 区域内添加动画
触摸目标
标准尺寸Tailwind实际大小
Material Design48×48 dpmin-h-12 min-w-12约 9 mm(推荐)
Apple HIG44×44 ptmin-h-11 min-w-11约 7 mm
WCAG 2.2 (AA)24×24 pxmin-h-6 min-w-6约 5 mm(最小值)

为什么? 成年人的指腹平均宽度约为 9 mm。小于 7 mm 的目标会导致“胖手指”误触。跨平台应用请使用 Material Design 的 48 dp;Apple 的 44 pt 是 iOS 专用的最小值。

性能

黄金法则
  1. 只为 transform 和 opacity 添加动画——由 GPU 加速
  2. 绝不要为以下属性添加动画:width、height、top、left、margin、padding
  3. 谨慎使用 will-change——仅在动画期间使用,结束后移除
  4. 模糊阈值:
    • ≤10px:适合动画
    • 11-20px:在移动设备/4K 屏幕上可能卡顿——请充分测试
    • 20px:避免用于实时效果;改用预先模糊的图像

  5. 简单过渡优先使用 CSS,而非 JS
关键陷阱
  • 高度动画:使用 layout 属性,而不是 animate={{ height }}
  • 不可见但可点击:opacity: 0 仍会接收点击——添加 pointerEvents: "none"
  • 到处使用 will-change:会导致图层激增,并使移动设备崩溃

详细示例请参见 references/recipes.md。

示例

references/recipes.md 中按类别整理了可直接复制粘贴的模式:

  • 常见 UI 模式:按钮按压、模态框进入/退出、错误抖动、交错列表、手风琴
  • 触控与交互:无障碍触控目标、触控设备上的悬停、即时工具提示
  • 布局动画:layout 属性、layoutId 共享元素、碰撞修复
  • Radix UI 集成:forceMount 模式、asChild、感知原点的弹出层
  • 无障碍:焦点时机、焦点恢复、减少动态效果的变体
  • 性能:高度动画(使用 layout)、不可见但可点击的修复、will-change
  • 退出模式:使用 forwardRef 的 popLayout、SSR 水合(initial={false})
  • 手势:带速度检查的滑动关闭、弹性拖动边界

AnimatePresence

模式行为使用场景
sync(默认)同时进入/退出交叉淡化、覆盖层
wait退出完成后再进入页面过渡、标签页
popLayout退出的元素脱离布局流列表项移除(配合 layout)
退出动画陷阱

退出动画需要 AnimatePresence——没有它,卸载会立即发生:

// ❌ Exit never runs
{isOpen && <motion.div exit={{ opacity: 0 }}>...</motion.div>}

// ✅ Wrap in AnimatePresence
<AnimatePresence>
  {isOpen && <motion.div exit={{ opacity: 0 }}>...</motion.div>}
</AnimatePresence>

SSR:使用 <AnimatePresence initial={false}>,以避免页面加载时播放动画。

反模式

不要这样做应改为原因
以 scale(0) 开始使用 scale(0.9) 或更高值避免“突然弹出”的效果
对 UI 使用 linear使用 ease-out 或弹簧动画线性动画感觉机械
动画时长超过 500ms控制在 300ms 以内感觉迟缓
工具提示延迟相同第一次:400ms,之后:0ms符合用户的心理预期
忽略减少动态效果设置始终使用 motion-safe:无障碍
动画化布局属性使用 transform: scale()性能更好
过度弹跳bounce: 0-0.2显得不专业

tailwindcss-animate

Tailwind v4:通过 CSS 中的 @theme 定义关键帧,而不是在配置文件中定义。

类别类
进入animate-in fade-in zoom-in-95 slide-in-from-top
退出animate-out fade-out zoom-out-95 slide-out-to-top
时序delay-150 duration-500
填充模式fill-mode-forwards fill-mode-backwards

与其他技能集成

时机技能原因
实现完成后code-quality确保代码通过检查
可复用模式docs-write记录组件 API
提交之前git-commit使用 feat(ui): 或 style:
集成问题search查找最新模式

输出

  • 产物:仅代码更改(不生成 .ada/ 输出)
  • 修改内容:组件动画、CSS/Tailwind 样式、Motion 配置
  • 类型:工作流技能(仅提供指导,不含脚本)

参考资料

内部
外部

评论

支持 Markdown