Communitygithub.com

Mad7droid/ux-motion

设计、实现并审查 UI 动效,涵盖过渡、手势、反馈和交互表面。在添加动效或修复缓慢、卡顿、分散注意力的交互时使用。跳过非视觉工作和图表动画。

ux-motion 是什么?

该技能提供了一套完整的 UI 动效设计、实现与审查规则,旨在帮助开发者创建快速、流畅且符合用户预期的交互体验。它基于“功能 UI 通常应保持在 120-180ms”的核心原则,优先使用 `transform` 和 `opacity` 属性以保持渲染性能。技能详细指导了如何根据交互频率决定是否添加动效、如何选择时长与缓动曲线、如何实现手势交互及处理中断,并强调必须通过 `prefers-reduced-motion` 为偏好减少动效的用户提供替代方案。该技能适用于所有使用 CSS 和 JavaScript 进行前端开发的平台(如 Web、React Native),其规则可通过项目中的 `AGENTS.md` 或 `CLAUDE.md` 文件进行灵活覆盖,确保动效设计既遵循最佳实践又能适应具体产品需求。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Mad7droid/mad-ux-motion/tree/main/skills/ux-motion

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

UX 动效

在设计并编写交互时应用这些规则。首先检查项目中的动效令牌:仓库中的 AGENTS.md、CLAUDE.md、令牌文件以及设计文档会覆盖下面的默认值。

始终在线的核心规则

  • 默认决策:功能 UI 通常位于 120–180ms 区间。项目令牌优先。
  • 为空间连续性、状态变化、输入反馈或避免突兀的闪烁而添加动效。
  • 优先使用命名的 transform 和 opacity 过渡。切勿使用 transition: all。
  • 进入的界面应减速;退出的界面应加速。退出动画可以更短。
  • 缩放的起始界面靠近 scale(0.96),绝不能从 scale(0) 开始。
  • 在 prefers-reduced-motion: reduce 下,动效应可被替换;保留理解能力和键盘访问。
  • 为拖拽操作捕获指针,防止多点触控干扰,并在真实硬件上测试手势。
  • 在编写动效或操作通用浮层之前,请完整阅读此文件。仅当涉及剪裁路径、3D、WAAPI 或性能深入探讨时,才使用 REFERENCE.md。

1. 判断是否值得添加动效

将曝光频率作为约束条件:不断重复的操作应瞬时或接近瞬时完成;偶尔出现的界面可以建立空间连续性;罕见的解释性时刻可以承载更多个性。动效必须用于阐明变化、确认输入、保留位置或防止突兀的出现。如果它不满足这些条件,请移除它。不要让键盘快捷键等待装饰性动效。

2. 选择时长

120–180ms 区间是一个默认决策:它有意比 Material 3 发布的 short3 (150ms)、short4 (200ms) 及标准过渡范围 (250–400ms) 更紧凑。这表达了对缓慢功能 UI 的偏好,而非发布的无障碍或平台要求。

界面起始点
按下反馈100–140ms
工具提示或小弹出框120–160ms
菜单或下拉菜单140–180ms
模态框180ms
面板180ms;若穿越视口大部分区域,最长可达 250ms

退出动画使用较短的一端。这些是默认值,而非覆盖产品令牌。

3. 选择缓动

进入的界面应带有强调效果并平稳停止(减速);退出应迅速清除(加速)。Material 3 明确命名了这些方向:

:root {
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-enter: cubic-bezier(0.05, 0.7, 0.1, 1); /* emphasized-decelerate */
  --ease-exit: cubic-bezier(0.3, 0, 0.8, 0.15); /* emphasized-accelerate */
}

仅对类时间进度使用 linear。对经过刻意中间点的状态使用 ease-in-out 曲线。避免仅凭名称选择曲线:检查绘制的形状和运动方向。

4. 保持渲染低成本

优先使用 transform 和 opacity,它们可以停留在合成器上。命名属性并将布局排除在动画之外。避免对 top、left、width、height、margin 或 padding 进行动画,除非布局变化本身是目的且其成本已接受。对于固有高度,可以使用包装器将 grid-template-rows: 0fr 过渡到 1fr,内部包装器设置 min-height: 0 并由 overflow: hidden 修剪。这仍需执行布局;请进行性能分析,而非将其视为仅合成器的快捷方式。will-change 应晚用、短用,且仅在性能分析证明其有益后使用;图层会消耗资源。

5. 确保状态正确

  • 为可按压控件提供可见反馈;使用现有的颜色、边框或阴影状态,或在其合适时使用小幅度的 scale(0.98)。不要覆盖定位变换。
  • 保留可见的焦点、键盘激活和禁用行为。动画不能延迟焦点放置、Escape 处理或语义状态更新。
  • 弹出框、菜单和工具提示通过 transform-origin 从锚点展开;居中的模态框从中心展开。在状态变化期间保持原点稳定。
  • 偏好对可重触发状态使用过渡。对自包含事件使用关键帧。
  • 使用 @media (hover: hover) and (pointer: fine) 限制仅悬停的交互。
  • 对于进入元素,在支持 @starting-style 的地方使用它,或者使用一个挂载状态,使初始样式在过渡开始前可被观察到。

6. 减少动效意味着有替代方案

prefers-reduced-motion 设置涵盖动效被移除、减少或替换;大规模平移和缩放可能引发前庭刺激。在能够解释状态的情况下,用透明度与颜色变化替代移动与缩放。保持焦点、加载和可见性变化可理解。不要仅仅因为用户要求减少动效就让元素消失。在 JavaScript 驱动的动画以及 CSS 中都应尊重此偏好,包括页面打开时偏好改变的情况。不要依赖 transitionend 事件来完成关键状态变更:过渡可能被禁用或取消。将覆盖范围限定到受影响的组件,而非全局强制每个动画都使用极短时长。

7. 手势

当拖拽开始时调用 setPointerCapture():后续指针事件将继续定向到捕获元素,直到释放。根据调整后的速度或距离规则进行关闭;没有通用的轻拂常量,因此要在实际设备上校准。通过阻尼而非硬边界来限制运动。一旦手势拥有指针,忽略额外的触控点。让用户能反转正在执行的手势。通过处理 pointercancel 和 lostpointercapture 来清除拖拽状态。为手势轴选择合适的 touch-action,避免不必要地阻止页面滚动;提供按钮或键盘等效操作。

8. 处理中断与弹簧

快速打开/关闭/重新打开应稳定在最新的请求状态。从当前视觉状态重新定位目标,而非从头开始重播。在替换或卸载时取消过期的回调、监听器和动画;旧的退出动画不能移除新打开的界面。根据组件的焦点生命周期,将隐藏或退出的内容移出键盘导航。

当直接操作或连续性需要时,可使用弹簧动画,但要尊重项目的库。弹簧参数在不同引擎间存在差异:不要盲目复制 stiffness 和 damping 值。在实际组件上调整稳定时间和超调量;避免文字密集界面出现弹跳,并在减动效下禁用移动。

9. 完成前验证

以 4 倍慢速回放,检查属性是否同时完成并从正确位置开始。快速切换以暴露卡顿。在开发者工具中模拟减动效。模拟拖拽超出边缘、取消、添加第二个触控点,并在物理设备上测试。对于运行时计算的动画值,请查阅 REFERENCE.md。说明实际执行了哪些检查,以及哪些需要在浏览器或物理设备上执行;单靠代码审查无法确定感知平滑度。

审查输出

在审计代码时,提供一个紧凑的表格,最严重的问题排在首位:

文件:行号现状修改为原因
Menu.tsx:18transition: all 300ms命名属性和项目令牌避免意外的布局动画

仅报告代码中可见的问题。如果差异清晰干净,则如实说明,而非编造问题。

由 mad7droid 精心整理。

相关技能