主题导航

Motion

动效

动效不是装饰,而是对操作的回应。瑚琏将缓动曲线与时长收敛成 token,让 CSS 工具类和 motion 动画保持同一种手感。

先问:该不该动

按用户一天看到它多少次决定,而不是按好不好看决定。高频动作上的动画只会让软件显慢。

频率典型场景结论
每天 100+ 次⌘K 命令面板、键盘快捷键不做动画
每天几十次hover 态、列表导航去掉或大幅削减
偶尔对话框、抽屉、Toast常规动效
罕见 / 首次引导、成功庆祝可以有惊喜
Command 面板刻意不做缩放进场,只保留 150ms 淡入。键盘高频入口不应被位移动画拖慢。

缓动曲线

悬停轨道即可比较手感。默认 ease-out 被替换为更果断的统一曲线。

减速(默认档)

ease-outcubic-bezier(0.16, 1, 0.3, 1)

进场 / 退场 / hover / 按压 —— 起步即最快,用户第一眼就看到位移,因此「感觉」比同时长的其它曲线更跟手。不确定用哪条时用它。

加速后减速

ease-in-outcubic-bezier(0.65, 0, 0.35, 1)

元素在屏内位移 / 形变(不涉及出现与消失)。两端都平缓,像真实物体起步与停稳。

抽屉(iOS / Ionic)

--ease-drawercubic-bezier(0.32, 0.72, 0, 1)

整屏尺度的滑入滑出:Drawer、ActionSheet。尾段比 ease-out 长得多,大面积位移才不会「冲到位再急停」。

不要使用 ease-in。它在用户最关注的开头阶段最慢,同样时长会比 ease-out 显得迟钝。

时长

交互动效控制在 300ms 内。180ms 的下拉比 400ms 的下拉感觉更快。

Token时长工具类用于
fast150msduration-150按压反馈 / 贴身微交互(100–160ms)
base200msduration-200浮层进出场:Tooltip、Popover、Select、Menu
slow300msduration-300大块转场:Drawer / ActionSheet 面板滑动
entrance600msduration-600首屏逐级揭示 / 滚动入场(非交互反馈,可从容)

按压反馈

任何可按下元素都应立即回应,否则界面像没有收到操作。

普通控件按下缩到 0.97,大卡片使用 0.99,避免子元素一起缩放时产生跳动。

// 已经使用 motion 的组件
import { pressable } from "@hulianui/ui";
<m.button whileTap={pressable.whileTap} transition={pressable.transition} />

// 不引入 motion 运行时的纯 CSS 方案
import { pressableClass } from "@hulianui/ui";
<button className={cn("…", pressableClass)} />
pressableClass 自带完整的 transition-property。请把它放在 cn() 末尾并替换原有 transition-colors。

浮层从触发器长出

锚定触发器的浮层应从触发器方向展开,而不是从自身中心展开。

/* Base UI 已在 Positioner 上提供原点,直接接入即可 */
<Popup className="origin-[var(--transform-origin)] data-[starting-style]:scale-95 …" />
Dialog、AlertDialog 与 Modal 不锚定触发器,应保持中心原点。进场也不要从 scale(0) 开始;scale(0.95) 配合透明度更自然。

无障碍

减少动效不等于移除所有反馈。

在 prefers-reduced-motion 下保留帮助理解的透明度与颜色过渡,并去掉位移动画。