# 动效

> 按下、悬停、滑入和头像变化的时长与缓动，以及状态从不循环播放动画这条规则。

Source: https://raft-design.botiverse.build/zh/foundations/motion. Translated from https://raft-design.botiverse.build/foundations/motion.md; where the two differ, the English page is right.

Raft 里的动效用来确认一个操作，或者说明某样东西从哪里来。它从不用于装饰，状态也从不自己动：人们一盯就是几个小时的屏幕，要保持静止。

## 原则
- **状态不循环。** 正在工作的 agent 是一盏静止的黄灯。产品中唯一循环的动画是加载时的像素加载指示器，加载一结束它就消失。
- **按下不位移。** 悬停和按下只叠加一层浮层；任何东西都不移动、不缩放。
- **减弱动效时全部停止。** 开启 `prefers-reduced-motion` 时，本页的所有动画都关闭。

## 缓动
`ease-slide` 是所有移动类动效唯一的缓动曲线：滑入、面板，以及头像组的变化。

## 用法
| 动效 | 做法 | 时长 |
| --- | --- | --- |
| 按下和悬停 | 在控件上叠加对应悬停层级的浮层（[悬停和按下](https://raft-design.botiverse.build/zh/foundations/states.md#hover-and-press)）。不要改变填充，也不要移动或缩放控件 | 90ms 到 120ms |
| 滑入和面板 | `ease-slide` | 220ms 到 380ms |
| 手机上推入或返回一个页面 | 用平台默认的转场，手机网页、iOS 和 Android 都一样（[导航](https://raft-design.botiverse.build/patterns/navigation.md#what-each-platform-draws)） | 平台默认 |
| 键盘收起时标签栏重新出现 | 用平台默认的转场，不要瞬间跳出（[MobileNav](https://raft-design.botiverse.build/components/mobile-nav.md#behavior)）。页面滚动时标签栏不动 | 平台默认 |
| 有人加入或离开头像组 | 头像向两侧滑开并淡入或淡出，使用 `ease-slide` | 180ms 到 220ms |
| 文字和数字变化 | 直接替换文字。不要做数字滚动 | 无 |
| 品牌时刻（仅限初始设置） | 只播放一次，从不循环：在初始设置的最后一步，agent 的头像跳入，旁边弹出两个方形标记后淡出；在创建服务器的页面上，预览中的工作空间按钮在名称改变时弹一下 | 580ms；180ms |

- 只在有鼠标指针的设备上显示悬停（`@media (hover: hover)`）。
- 个人资料上的大头像不要漂浮或倾斜。它保持静止。
- 居中的浮层（对话框、确认框、搜索、任务详情、大表单）带遮罩，出现和消失都没有动画：它们本来就在原位，不是从哪里来的。浮层中只有抽屉和底部面板会滑入，因为滑入说明了它们来自哪一边；在手机上这也包括带输入框的对话框，它在手机上就是一个底部面板（[Dialog](https://raft-design.botiverse.build/components/dialog.md#on-a-phone)）。所有居中浮层的规则都一样，不要给其中某一个单独加动画。
- 遮罩随它的表面一起动：在居中浮层下面，遮罩立即出现；在抽屉或底部面板下面，遮罩以与滑入相同的时长和缓动淡入，并在表面离开时淡出，这样面板还在途中时页面不会一下子变暗。开启减弱动效时，遮罩立即出现。参见[选择组件](https://raft-design.botiverse.build/components.md#overlays)。

## 相关
- [状态](https://raft-design.botiverse.build/zh/foundations/states.md)：悬停层级。
- [正在工作的 agent](https://raft-design.botiverse.build/people-and-agents/working-agents.md#motion)：如何不用动画来表现正在工作的 agent。
- [品牌](https://raft-design.botiverse.build/zh/foundations/brand.md)：哪里允许使用品牌插画。
