Back to skills
SKILL.md
Zack Motion Taste
ASecurity动效决策框架:该不该动、动什么、动多久、用什么曲线、怎么打断、怎么退出、性能怎么保。包含时长与缓动对照表、属性选择、手势与弹簧、reduced-motion 处理。当需要添加动画、让组件「活」起来、做转场,或动效显得卡顿/廉价/多余时使用。仅做动效判断,不改视觉风格。
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added October 12, 2026
Works with
Security analysis
100/100npx -y skills add yckonnnnn/zack-design-skills --skill zack-motion-taste --agent claude-codeAre you the author of Zack Motion Taste?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/yckonnnnn-zack-motion-taste)---
name: zack-motion-taste
description: "动效决策框架:该不该动、动什么、动多久、用什么曲线、怎么打断、怎么退出、性能怎么保。包含时长与缓动对照表、属性选择、手势与弹簧、reduced-motion 处理。当需要添加动画、让组件「活」起来、做转场,或动效显得卡顿/廉价/多余时使用。仅做动效判断,不改视觉风格。"
license: MIT
metadata:
author: Zack
homepage: https://github.com/yckonnnnn/zack-design-skills
version: "1.0.0"
---
# 动效判断
**默认答案是「不动」。** 动效只有在能解释状态变化、或表达物理因果时才加。加得对,界面显得贵;加得错,界面显得廉价——而且廉价得更明显。
**最重要的信号**:如果一个动效让人注意到「这里有个动画」,它就是错的。好的动效是让人注意到「这件事发生了」。
---
## 一、先问四个问题
按顺序,任何一个答不上来就不做。
| # | 问题 | 答不上来意味着 |
|---|---|---|
| 1 | 这个动效在**解释什么**?(从哪来、到哪去、什么变了) | 纯装饰,删掉 |
| 2 | 用户在这个动效期间**能操作吗**? | 可能是阻塞式动画,需要重新设计 |
| 3 | 它**多频繁**出现? | 高频(> 每天几十次)→ 时长要更短或干脆不做 |
| 4 | 关掉它,用户会**困惑**吗? | 不会困惑 → 它是装饰,删掉 |
**高频交互的动效要短到几乎察觉不到**(80–140ms)。一天点 200 次的按钮,每次 300ms 的动画等于浪费用户一分钟。
---
## 二、什么时候该动
| 目的 | 该做 | 例子 |
|---|---|---|
| **解释空间关系** | ✅ 必须做 | 弹层从触发它的按钮方向长出;抽屉从边缘滑入 |
| **确认操作已生效** | ✅ 必须做 | 按钮按下反馈、提交成功、复制成功 |
| **引导注意力** | ✅ 谨慎做 | 新内容进入、错误提示 |
| **表达物理真实** | ✅ 谨慎做 | 拖拽跟手、甩出带惯性、边界回弹 |
| **保持连续性** | ✅ 必须做 | 列表项增删时其他项平滑移动;布局切换不跳 |
| **纯装饰** | ❌ 不做 | 元素进视口就淡入上移、logo 旋转、背景粒子 |
| **掩盖加载** | ⚠️ 有条件 | 优先用骨架屏(有信息),而不是转圈(无信息) |
---
## 三、动什么属性
只动这两类:
| 类别 | 属性 | 说明 |
|---|---|---|
| **合成器属性**(首选) | `transform`(translate/scale/rotate)、`opacity` | 不动布局,可跑在合成线程 |
| **可接受** | `filter`(blur/brightness)、`clip-path`、`color`、`background-color` | 视情况,注意代价 |
| **禁止** | `width`、`height`、`top/left`、`margin`、`padding`、`box-shadow`(大范围) | 触发布局/重绘 |
需要动尺寸时,用 `transform: scale()` 替代宽高,或先用 `grid-template-rows: 0fr → 1fr` 做高度过渡。
**永远不要用 `transition: all`。** 它会把你不想要的东西一起动了,并且在需求变化时产生意外。
```css
/* 错 */
transition: all 0.3s ease-in-out;
/* 对 */
transition: transform 180ms cubic-bezier(0.22, 1, 0.36, 1),
opacity 180ms cubic-bezier(0.22, 1, 0.36, 1);
```
---
## 四、时长
| 距离 / 尺度 | 时长 | 说明 |
|---|---|---|
| 微反馈(按下、勾选、切换) | **80 – 140ms** | 必须快到像即时 |
| 小元素(tooltip、下拉、标签) | **140 – 200ms** | |
| 中元素(卡片、面板、抽屉) | **200 – 300ms** | |
| 大元素(模态、整页转场) | **300 – 420ms** | |
| 超大(全屏叙事) | **420 – 600ms** | 超过 600ms 一定拖沓 |
| **退出** | **比进入快 30–50%** | 用户已经决定离开了,别让他等 |
**核心规则**
1. **越近越快。** 元素移动的物理距离越大,时长越长(近似线性,约 1ms / 1px,量级参考)。
2. **退出比进入快。**
3. **高频比低频快。**
4. 超过 400ms 的动画,用户开始感觉界面变慢。
---
## 五、缓动
```css
:root {
/* 标准:进入/退出,快起慢收,最通用 */
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
/* 进入屏:从静止起步 */
--ease-in: cubic-bezier(0.55, 0, 1, 0.45);
/* 双向:位置移动、拉伸 */
--ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
/* 强调:弹层出现、需要一点俏皮 */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
```
| 场景 | 曲线 |
|---|---|
| 元素进入(出现、展开) | `--ease-out`(快起慢收) |
| 元素退出(消失、收起) | `--ease-in`(慢起快收) |
| 位置移动 / 尺寸变化 | `--ease-inout` |
| 弹层、需要个性 | `--ease-spring`,且回弹幅度要小 |
| 拖拽跟手 | 无缓动(1:1 跟手) |
| 甩出惯性 | 弹簧或 decay |
**禁止** `linear`(除进度条、加载旋转外)和浏览器默认的 `ease-in-out`。默认曲线是「没想过」的证据。
### 弹簧参数(如果用弹簧)
```
交互跟手 / 拖拽: stiffness 400–600, damping 30–40, mass 1
弹层出现: stiffness 300–400, damping 28–34
轻微俏皮: stiffness 250–350, damping 18–24 (回弹 1–2 次,不要更多)
```
回弹超过 2 次就是「玩具感」。高客单/专业产品用 damping 高一些,几乎不回弹。
---
## 六、进入 / 退出 / 打断
### 进入
- 用 `--ease-out`,时长按尺度取。
- **方向要有意义**:弹层从触发按钮的方向长出;从右侧滑入的抽屉,退出也要回右侧。
- 不要所有东西都「淡入 + 上移 20px」。这是默认解,做多了等于没有动效设计。
### 退出
- **比进入快 30–50%。**
- **不要在退出时做复杂的编排**,用户已经在看下一个东西了。
- 退出必须真的移除元素(`display: none` 或从 DOM 移除),不要留下不可见的可点击区域。
### 打断(最重要、最少人处理)
用户在动画途中再次操作时:
- **不要阻塞。** 输入必须始终可响应。
- **从当前位置重新开始**,不要跳回起点。用 `Element.animate()` 的 currentTime,或读 `getComputedStyle` 的当前 transform 作为起点。
- **可中断的动效不要用 CSS `transition`**(无法优雅中途转向),改用 Web Animations API 或 JS 弹簧。
- 拖拽中途松手:从**当前速度**接续惯性,不要从零加速。这就是「跟手」和「卡」的区别。
```js
// 从当前状态继续,而不是把元素拉回起点
const el = document.querySelector('.sheet');
const current = getComputedStyle(el).transform; // 读取中断时的位置
el.style.transform = current;
requestAnimationFrame(() => el.classList.remove('open'));
```
---
## 七、reduced-motion
**这不是可选项。** 前庭功能障碍用户会因为视差和大幅位移产生生理不适。
```css
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
但要**有策略地降级,不是全删**:
| 原动效 | 降级为 |
|---|---|
| 位移进入 | 纯透明度变化(opacity 仍在,且有意义) |
| 视差 / 滚动联动 | 完全静态 |
| 弹簧 / 回弹 | 直接到位,无缓动 |
| 自动轮播 | 停止自动播放 |
| 加载旋转 | 保留(这是必要信息) |
**判断标准**:降级后,信息不能丢失。位移用来表达「从哪来」时,必须换一种方式表达(例如直接出现 + 高亮)。
---
## 八、性能
- 只动 `transform` / `opacity`;需要提前提示浏览器用 `will-change: transform`,但**用完要移除**(长期挂着会吃内存)。
- 滚动相关动效:用 `IntersectionObserver`(进入/离开)和 `scroll-timeline`,**不要**在 `scroll` 事件里直接读 `scrollTop` 改样式。
- 滚动监听如果必须用,配 `passive: true`,并在 `requestAnimationFrame` 里合并更新。
- 目标:**动画期间保持 60fps**,单帧预算 16.7ms。长任务会让动画掉帧。
- 内容进入视口的滚动揭示动效:`translateY ≤ 12px`、opacity 起始 ≥ 0(不要从 0 开始,会闪),时长 ≤ 400ms。
- **首屏关键内容不要用动效延迟。** LCP 元素加了 `animation-delay` 会直接拉低性能评分。
### 性能预算
不谈数字的性能建议等于没有建议。以下是可验收的线:
| 指标 | 目标 | 动效相关的常见违规 |
|---|---|---|
| **LCP** | < 2.5s | 首屏元素带 `animation-delay`;展示字体延迟加载导致文字后到 |
| **INP** | < 200ms | 长驻动效循环占主线程;`scroll` 事件里同步读写样式 |
| **CLS** | < 0.1 | 动效改变元素尺寸(动 `height`);字体加载后回流 |
| 动画帧率 | 60fps(单帧 ≤ 16.7ms) | 动 `width/height/top/left`;大面积 `filter: blur()` |
| 长驻动画数量 | 同一屏 ≤ 1 个 | 多个 CSS 无限循环同时跑 |
| 字体加载 | `font-display: swap` + 预加载关键字体 | 无 `font-display`,文字在字体到达后整体位移 |
**测量,而不是声称。** 说「优化了性能」之前,先给出改前改后的实测值(Chrome DevTools Performance 录制,或 `PerformanceObserver` 读 LCP/INP/CLS)。测不了就写「未验证」。
### 不要为了让回答显得果断而编一个时长
遇到「这里到底该 200ms 还是 300ms 说不准」的情况:
- **正确**:给出一个范围(「200–300ms 之间,我倾向 240」),并说明需要实机验证。
- **正确**:写进「没验证的部分」。
- **错误**:精确到「237ms」来显得有把握。
编出来的精确值会让后面所有人以为它经过验证。**不确定就说不确定**,这比一个假的精确值有价值。
---
## 九、自检
- [ ] 每个动效都能回答「它在解释什么」吗?
- [ ] 有没有出现 `transition: all`?
- [ ] 退出是否比进入快?
- [ ] 用了 `linear` 或默认 `ease-in-out` 吗?
- [ ] 高频交互的时长是否 ≤ 140ms?
- [ ] 动画途中再点一次,会跳回起点吗?(会 = 不合格)
- [ ] `prefers-reduced-motion` 处理了吗?降级后信息还完整吗?
- [ ] 只动了 `transform` / `opacity` 吗?
- [ ] `will-change` 有没有留在元素上不撤?
- [ ] 首屏 LCP 元素有没有被动画延迟?
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.