动效
动效只做三件事:告诉你按到了、告诉你东西从哪来到哪去、告诉你什么在变。三档时长、一组语义缓动、一条按压时间线、三类浮层进出场——全部是令牌与共享关键帧,皮肤只引用,不自己发明。
时长与缓动
| 令牌 | 取值 | 说明 |
|---|---|---|
--xh-duration-fast | 120ms | 微反馈:换面、按下、退场 |
--xh-duration-normal | 200ms | 入场、释放、位移 |
--xh-duration-slow | 320ms | 大面积滑入:Drawer、Sheet |
| 令牌 | 取值 | 说明 |
|---|---|---|
--xh-ease-standard | cubic-bezier(0.2, 0, 0, 1) | 连续变化:颜色、按下 |
--xh-ease-out | cubic-bezier(0, 0, 0.2, 1) | 入场 |
--xh-ease-out-strong | cubic-bezier(0.23, 1, 0.32, 1) | 强入场、释放回弹 |
--xh-ease-out-fluid | cubic-bezier(0.32, 0.72, 0, 1) | 大面积滑入 |
--xh-ease-in | cubic-bezier(0.4, 0, 1, 1) | 退场 |
--xh-ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) | 扫过:进度、指示条移动 |
--xh-ease-out-back | cubic-bezier(0.34, 1.56, 0.64, 1) | 落定:拖动结束的轻微过冲 |
组件不直接取这两组原语,取语义层的 --xh-motion-*:duration-enter / exit / micro / slide / press / release、ease-enter / enter-strong / exit / slide / sweep / press / release / settle / continuous、位移 distance-sm / md(4 / 8px)、缩放 scale-enter 0.96 / exit 0.98 / press 0.97 / drag 1.12、错开起播 stagger-step。CSS 串与 JS 侧 @xihan-ui/motion 的采样函数同一份来源,门禁 check-motion-source 比对。
按压触感
定尺的独立动作控件(按钮、把手、方框、星、日历格、色块、排序钮)投影 Action Control 配方,按下与释放走同一条时间线:
| 阶段 | 时长 | 结果 | 缓动 |
|---|---|---|---|
| 按下 | 120ms(--xh-motion-duration-press) | scale 1 → 0.97,底进入 active | --xh-motion-ease-press |
| 释放 | 200ms(--xh-motion-duration-release) | scale 0.97 → 1,底回到 hover / rest | --xh-motion-ease-release |
- transform origin 固定居中;指针
:active、键盘 Space / Enter 与 Headless 投影的data-pressed三者一致。 - 行级条目与 disclosure trigger(菜单项、树节点、表格行、手风琴标题)只换面,不缩放整个条目;不允许零反馈。
- 不用点击波纹;不允许组件自设 0.94 / 0.96 / 0.98 等缩放。
- 业务事件不等动画结束:按下首帧先于异步 loading 可见;pending 后锁定重复操作,不持续缩放。
- hover + pressed 时 pressed 优先;focus-visible + pressed 保留焦点环、按压只改内部表面;selected / danger + pressed 保留各自身份,在其上派生 active 面。
Disclosure
- Surface 级展开(Accordion、Collapsible、Reasoning、ToolCall)内容走
grid-template-rows: 0fr → 1fr:入场--xh-motion-duration-enter+--xh-motion-ease-enter-strong,退场--xh-motion-duration-exit+--xh-motion-ease-exit;指示器旋转与内容同档。 - 密集树形展开(Tree、TreeSelect、JsonViewer、SideNav 内联子层)不动高度,只旋转指示器
--xh-motion-duration-micro。
浮层进出场
按锚定关系三分,关键帧集中在 family/motion.css,皮肤不得重定义:
| 关系 | 关键帧 | 组件 |
|---|---|---|
| 锚定列表 / 菜单 | xh-overlay-slide-in / out | Menu、Select、Combobox、Cascader、ContextMenu、Menubar、Mention、TreeSelect、Date / Time picker、Tooltip |
| 锚定面板 | xh-overlay-pop-in / xh-pop-out | Popover、HoverCard、Popconfirm、Tour、Command |
| 无锚定弹出 | xh-pop-in / out | NavigationMenu、SideNav popout、FloatingPanel、FloatButton 列表、Pagination 弹层 |
遮罩与全屏面 xh-fade-in / out;Dialog / Notification = 位移 md + scale-enter;Drawer 入场 --xh-motion-duration-slide + --xh-motion-ease-slide、退场 --xh-motion-duration-exit + --xh-motion-ease-exit。退场由 Presence 等动画真正结束再卸载节点。
弹簧与 JS 动画
指针跟手的东西(拖动、滑杆、轮播惯性)不用固定时长,用 @xihan-ui/motion 的弹簧:由刚度、阻尼与质量算终点,中途换目标不跳帧。animate() 默认取 durations.normal,@xihan-ui/animations 的配方默认取 durations.slow。见 动效原语 与 动画层。
减弱动效
data-motion="reduce"(偏好 system 时跟 prefers-reduced-motion)取消位移与缩放,保留即时换面:按下仍然换底、浮层仍然出现,只是不再滑动与缩放。JS 侧经 resolveMotionPreference 读同一个值——退场租约、贴底滚动、数字动画、加载弧线、背景层全部走这一条通道,产品自己的"减弱动效"设置用 setMotionOverride 一处设置、处处生效。
相关
- 阴影与材质 · 组件家族与模式
- 指南:动效原语 · 动画层 · 设计令牌与主题 · 点击触感
