mcpField
A
awwwards-motion-design

awwwards-motion-design

github.com/yu-369设计与 UI99252 次安装12 周前更新
代码仓库

关于 awwwards-motion-design

面向编码 Agent 的网页动效设计技能,通过动效审查、编排规划和实现指导组织工作。重点是保持动效风格一致、让动画服务于功能,并考虑减少动态效果偏好。

主要功能

  1. 01审查动效需求
  2. 02设定统一的动效风格
  3. 03规划页面元素的动画覆盖
  4. 04使用错落编排与弹簧缓动
  5. 05考虑减少动态效果偏好

适用场景

  1. 01规划营销落地页动效
  2. 02为交互界面添加一致反馈
  3. 03检查页面动效覆盖情况

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yu-369/vibecurb --skill awwwards-motion-design

安装后在 Claude Code 中输入/awwwards-motion-design确认已加载。

详细介绍

Awwwards 级别的动效设计

当用户要求添加动画、过渡、微交互、滚动效果、页面过渡、动态排版、视差效果、悬停物理效果、加载序列,或任何能让 Web 界面显得生动且有质感的效果时,此技能就会触发。动效是品质的语言——它让静态页面与精心打造的体验拉开差距,而后者就像是由每个项目收费 20 万美元的工作室亲手打造的一样。


工作流程

┌───────────────────────────────────────────────────────────────────────┐
│                                                                       │
│   BRIEF IN ──→ Phase 1: Motion Audit ──→ Phase 2: Choreography      │
│                  (classify, extract        (sequence map, timing      │
│                   motion intent)            sheet, easing palette)    │
│                                                                       │
│                              ──→ Phase 3: Build                       │
│                                   (implement layer by layer:          │
│                                    entry → scroll → hover →          │
│                                    transitions → ambient)            │
│                                                                       │
│                              ──→ Phase 4: Motion Diff                 │
│                                   (60fps check, feel check,          │
│                                    reduced-motion audit)             │
│                                                                       │
│   Each phase has a ✓ Quality Gate. Failing a gate blocks the next.    │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

核心准则

开始编写任何代码之前,请牢记以下准则。它们优先于一切审美偏好。品质标准是 Apple 发布会演示、Linear 应用、Stripe 首页、Vercel 控制面板、Raycast。如果你的动画放在 apple.com 上显得格格不入,那就不够好。

Apple 标准。 Apple 不使用通用的 CSS 过渡效果。Apple 使用弹簧物理效果——动画会像实体一样过冲、稳定下来,并自然舒展。iOS 上的每次交互都让人感觉像是在触碰真实物体:按钮会被按压,面板会带着惯性滑入,元素会轻轻弹动后稳定下来。你的动画也必须达到这种同样真实、可触的质感。如果元素移动时给人的感觉是“数字化”或“计算出来的”,而非“真实”或“鲜活”,那缓动就不对。

每个动画都必须有理由。 如果你无法用功能性理由回答“它为什么要动?”(引导注意力、传达状态变化、提供反馈、建立空间关系),就移除这个动画。没有目的的动效只是噪声。

最好的动画是无形的。 用户不应该想“这个动画真不错”,而应该觉得“用起来真舒服”。如果动画吸引用户注意的是它自己,而不是内容,那就太过了。Apple 从不会让你等动画结束。动画应服务于交互,而不是反过来。

一致性至关重要。 如果一页上的所有动画都使用相同的缓动风格、相同的强度和相同的动效语言,就会让人觉得出自同一间工作室。若淡入上移、弹簧弹跳、向左滑入和缩放弹出并存,则会显得像是委员会的作品。选定一种动效风格,并贯彻到底。 少一些动画,但保持一致,永远胜过面面俱到却风格各异。若必须二选一,就牺牲覆盖面来保持一致性——8 个协调精美的动画,胜过 30 个彼此不搭的动画。

优先使用弹簧物理效果,而非 cubic-bezier。 将 cubic-bezier(0.25, 0.1, 0.25, 1) 奉为缓动巅峰的时代已经结束。Material Design 3 Expressive 已转向基于弹簧的动效。Apple 从 iOS 7 起就开始使用弹簧动画。Web 也已跟上:CSS linear() 能实现带有过冲和稳定效果的真实弹簧物理效果。每个主要动画都应使用基于弹簧的缓动。只有在环境动效或背景动效不适合弹簧过冲时,才使用 cubic-bezier。

缓动就是动画本身。 300 毫秒的线性过渡与 300 毫秒的弹簧过渡时长相同,但风格截然不同。曲线决定了 20 万美元工作室打造的网站与模板的区别。不存在所谓的“默认”缓动。每条曲线都是经过审慎考虑的选择,都有其特定的情感特征。

错开动画能建立层级。 多个元素同时播放动画时,不能让它们全都同时移动。错开效果相当于动效中的视觉层级——它会告诉视线先看哪里,再看哪里,最后看哪里。Apple 会以毫秒级精度错开动画,你也应该如此。

动效应尊重用户。 每个动画都必须遵循 prefers-reduced-motion 设置。没有例外。设置此选项的用户可能患有前庭障碍、对运动敏感,或只是偏好静止效果。减少动态效果不意味着完全不使用动画——而是避免位移、视差、缩放和弹簧过冲。可以接受缩短时长、仅改变不透明度的淡入淡出效果。 每个元素都值得分配动画预算。 对营销/落地页而言,这意味着全面覆盖——每个可见元素至少要有一种动画形式(进入、滚动显现、悬停或环境动画)。在动画页面中,静态元素就像鲜活显示屏上的坏点。在功能性应用 UI 中,动画遵循频率门槛:

使用频率动画预算
每天 100 次以上(键盘快捷键、命令面板、核心导航)完全不加动画。永远如此。 速度就是体验。
每天数十次(悬停状态、列表导航、开关)极少——只提供快速、几乎察觉不到的反馈
偶尔使用(模态框、抽屉、提示消息、设置面板)使用缓动方案中的标准动画
罕见/首次使用(引导、空状态、成功、庆祝)充分发挥愉悦效果——弹簧、弹跳、大方的交错动画

硬性规则: 由键盘触发的操作绝不添加动画。每天打开/关闭 200 次的命令面板动画,会让用户逐渐厌恶它。最快的界面才是赢家。


动画覆盖要求

这是一条不可妥协的规则:每个可见元素都要有动画。 不是“大多数元素”,也不是“重要元素”,而是每个元素。逐个检查页面上的元素,并根据此表为它们分配动画。如果某个元素不在表中,至少也要为它添加由滚动触发的淡入效果。

→ 必需的元素动画映射

为页面上的每个元素填写此表。每行至少必须有一个 ✓。任何空行都表示实现不完整。

元素入场动画滚动显示悬停/聚焦状态氛围/微动效已分配
导航栏从顶部向下滑入并淡入-链接下划线滑入,菜单项弹簧式缩放-✓
Logo淡入(首个元素,延迟 0ms)-悬停时轻微缩放至 scale(1.05)-✓
导航链接从左到右依次淡入-下划线滑动并切换颜色-✓
主视觉标题逐词遮罩显示或拆分字符---✓
主视觉副文案向上淡入并去模糊(在标题之后依次出现)---✓
主视觉 CTA 按钮缩放并淡入(主视觉中的最后一个元素)-按压深度效果(压缩并添加内阴影)+ 上浮 + 点击时涟漪效果轻微的发光脉冲✓
主视觉背景缩放(1.05→1)并淡入(Ken Burns 效果平稳结束)缓慢视差-渐变变化或颗粒移动✓
版块标题-逐词遮罩显示或向上淡入并去模糊--✓
版块副文案-淡入上移(在标题之后延迟 80ms)--✓
正文段落-逐行显示或向上淡入--✓
卡片-依次向上淡入(每张卡片间隔 80ms)上浮(-4px)+ 阴影扩散 + 边框发光 + 3D 倾斜-✓
卡片图标/图片-缩放显示(卡片显示后)悬停卡片时轻微旋转或切换颜色-✓
卡片标题-随卡片一同显示悬停卡片时切换颜色-✓
卡片描述-随卡片一同显示悬停卡片时提高不透明度-✓
图片-遮罩裁剪擦除显示或缩放显示悬停时 Ken Burns 缩放-✓
按钮(全部)-随父元素向上淡入按压深度效果 + 上浮 + 阴影 + 点击涟漪效果-✓
行内链接-随父元素一同显示下划线滑动并切换颜色-✓
输入字段-随父元素向上淡入聚焦时边框发光 + 标签浮起-✓
徽章/胶囊标签-缩放并淡入悬停时切换背景颜色轻微弹跳浮动✓
分隔线-从中心向两侧展开(scaleX 0→1)--✓
推荐语-向上淡入并去模糊,同时滑入--✓
头像-缩放显示并播放边框环动画悬停时边框环脉冲-✓
统计数据/数字-数字递增动画(从 0 开始计数)--✓
页脚-向上淡入(最后一个版块)链接下划线滑入-✓
页脚链接-依次显示下划线滑入并切换颜色-✓
社交图标-依次缩放显示上浮并切换为品牌色-✓
背景形状---浮动动画 + 视差✓
装饰元素---旋转入场或缩放入场缓慢旋转或浮动
滚动指示器主视觉加载后淡入--轻柔循环弹跳✓
进度条-缓动展开宽度(scaleX 0→1)--✓
工具提示--从触发元素处向上浮起并淡入-✓
折叠面板-随父元素向上淡入悬停时切换边框/背景平滑展开高度✓
标签页-随父元素淡入切换背景指示器滑动 + 内容交叉淡化✓
模态框---背景遮罩淡入 + 内容缩放显示✓
Toast/通知---从边缘滑入 + 自动消失✓

⚠ 偏离警告: 最常见的失败是只为主视觉和第一个版块添加动画,然后让首屏以下的所有内容完全静止。每个版块都必须有滚动触发的显示动画。每个交互元素都必须有悬停反馈。从上到下检查整个页面,确认所有元素都已覆盖。如果滚动时发现某个版块只是“静置不动”,没有动画效果,则说明实现有问题。

→ 覆盖范围验证检查

构建完所有动画后,执行此项检查。打开页面,以自然的阅读速度从顶部滚动到底部。对于每个进入视口的元素:

  1. 它是否会进入视图时播放动画? 如果没有 → 添加滚动显现动画
  2. 它是否支持悬停? 如果支持 → 是否有悬停反馈?如果没有 → 添加悬停状态
  3. 它是否具有交互性(可点击、可聚焦)? 如果是 → 是否有激活/焦点状态?如果没有 → 添加这些状态
  4. 它是否是装饰元素? 如果是 → 是否具有环境动效(浮动、旋转、脉动)?如果没有 → 添加动效
  5. 它是否是文本元素? 如果是 → 是否至少具有淡入上移动画?如果没有 → 添加此动画

动画覆盖率达到 100% 的页面会让人感觉充满活力。覆盖率为 80% 的页面则会留下视觉上立刻可察觉的死角。


第一阶段:动效审查

编写任何代码之前,先对动效需求进行分类。

→ 对动效场景进行分类
字段你的答案
页面类型营销落地页 / 产品应用 / 作品集 / 电子商务 / 编辑内容 / 仪表板
动效密度极简(Apple 风格的克制)/ 适中(Stripe 级别)/ 丰富(Awwwards 实验风格)
主要动效目的引导注意力 / 传达状态 / 营造氛围 / 展示内容 / 带来愉悦感
滚动行为标准滚动 / 滚动联动动画 / 滚动接管式分区 / 粘滞显现
页面转场无(SPA 即时切换)/ 交叉淡化 / 滑动 / 变形 / 自定义序列
框架Vanilla CSS/JS / Framer Motion(React)/ GSAP / Motion One / 纯 CSS
→ 锁定动效个性(必须)

这是整个流程中最重要的决定。页面上的每个动画都必须具有相同的个性。混搭不同个性的页面,会让人觉得是三个不同的开发者分别为它制作了动画。

选择一种:

个性特征缓动核心时长范围标志性动作参考
利落型清晰、快速、没有过冲。每个动效都有实际用途,不做装饰。干净利落,如手术刀般精准。--ease-out + --ease-snap100-250ms即时反馈、锐利的交错动画Linear 应用、Raycast、Vercel 仪表板
物理型基于弹簧,触感鲜明,物体仿佛具有重量。动效会过冲、稳定、带有惯性。像触摸真实物体一样。--spring-snappy + --spring-smooth300-600ms(弹簧稳定时间)弹簧式进入、惯性拖动、按压压缩Apple.com、iOS、Dynamic Island
电影感戏剧化、循序渐进、富有表现力的显现。页面本身就是一场演出。滚动联动叙事。--ease-dramatic + --spring-smooth500-900msclip-path 显现、文本拆分、滚动固定序列Stripe 首页、Awwwards 实验风格

锁定后,这种个性将约束后续的一切:使用哪些曲线、速度如何、交错幅度多大、是否使用弹簧、是否使用环境动效。**不要混搭不同个性。**利落型页面中出现一个弹跳的弹簧元素,就是设计缺陷。电影感页面中出现一个 100ms 的工具提示瞬间吸附动画,也是设计缺陷。保持一致,才能让动效显得像是由「同一个人」设计的。

→ 识别动效层

浏览页面,为所有应当动起来的元素添加标记。将每个元素归入以下其中一层:

动效层涵盖内容优先级
进入首次绘制时的显现、首屏加载动画P0 - 必须有
滚动用户滚动时显现的元素、视差、粘滞序列P0 - 必须有
悬停/焦点按钮抬升、卡片倾斜、链接下划线、按压深度效果P0 - 必须有
状态页面转场、标签切换、模态框打开/关闭、手风琴、菜单P1 - 应当有
环境浮动元素、渐变变化、粒子系统、光标光晕P2 - 润色层
动能文本拆分、逐字显现、单词轮播P2 - 润色层
→ 输出动态简报

用 2-3 行说明动态策略。必须包含已锁定的个性名称。

"动态简报:PHYSICAL 个性。所有版块以交错的弹簧效果进入(--spring-snappy)。滚动触发显示,视口阈值为 20%。所有交互元素按下时都会压缩。版块标题以平滑弹簧效果显示文本。无环境粒子(与个性冲突)。核心缓动:进入使用 spring-snappy,状态变化使用 spring-smooth,仅悬停使用 ease-snap。"

✓ 质量关卡:审核

进入第 2 阶段前,请确认:

  • 动态背景已分类(页面类型、密度、用途)
  • 动态个性已锁定(Surgical / Physical / Cinematic)
  • 每个运动元素都已标记所属动态层
  • 页面上每个元素的元素动画映射表都已填写完毕——没有空行
  • 已撰写动态简报(包含个性名称)
  • 已选择框架

第 2 阶段:编排

动态就是编排。每个元素都有入场提示、时长、缓动曲线,以及与周围元素的关系。本阶段将制作时间表——页面的乐谱。

→ 缓动调色板

这是整个技能中最重要的部分。缓动调色板定义了页面上每个动画的情感语言。用错曲线就像在交响乐中弹错音符——即使不懂音乐的人也能感觉出来。

调色板分为三个层级,按质量排序。请使用浏览器支持范围内的最高层级。


第 1 层级:通过 CSS linear() 实现弹簧物理效果——黄金标准

Apple 使用这种效果。Material Design 3 Expressive 也使用这种效果。它能让价值 20 万美元的工作室网站与模板区分开来。CSS linear() 支持真正的弹簧物理效果,包括过冲和稳定——这是 cubic-bezier() 从根本上无法实现的。

/* BLUEPRINT: Spring-based easing palette via CSS linear()
   WHY: Real spring physics create motion that feels PHYSICAL.
   Objects in the real world don't follow cubic-bezier curves -
   they have mass, momentum, and elasticity. Springs overshoot
   their target and settle back, which reads as "alive" to the
   human eye. This is why every iOS animation feels tangible.

   These curves were generated from spring physics simulations
   with specific mass/stiffness/damping parameters. The linear()
   function plots the spring's position at discrete time steps,
   which the browser interpolates smoothly between. */

:root {
  /* 1. APPLE SNAPPY SPRING - Primary entrance/reveal easing
     Physics: mass=1, stiffness=400, damping=30
     Character: Explosive start, tiny overshoot (~2%), soft settle.
     This is the iOS sheet-present / notification-arrive curve.
     Use on: hero entries, scroll reveals, modal opens, everything
     that "arrives" on screen. This is your DEFAULT curve. */
  --spring-snappy: linear(
    0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%,
    0.938 16.7%, 1.017 19.4%, 1.067 22.5%, 1.089 26.0%,
    1.079 30.3%, 1.049 36.0%, 1.024 42.6%, 1.011 50.3%,
    1.004 59.2%, 1.001 69.3%, 1
  );
  --spring-snappy-duration: 0.55s;

  /* 2. APPLE SMOOTH SPRING - State changes, position shifts
     Physics: mass=1, stiffness=200, damping=24
     Character: Gentle acceleration, visible overshoot (~5%),
     two-phase settle. Feels like a precision instrument.
     This is the iOS page-transition / tab-switch curve.
     Use on: page transitions, tab switches, carousel slides,
     anything moving from position A to position B. */
  --spring-smooth: linear(
    0, 0.004, 0.016 2.3%, 0.063 4.7%, 0.141 7.2%,
    0.25 9.9%, 0.601 16.5%, 0.815 21.0%, 0.929 25.2%,
    0.987 29.0%, 1.025 33.5%, 1.042 38.0%, 1.04 43.5%,
    1.027 50.0%, 1.013 57.5%, 1.005 67.0%, 1.001 79.0%, 1
  );
  --spring-smooth-duration: 0.7s;

  /* 3. APPLE BOUNCY SPRING - Playful micro-interactions
     Physics: mass=1, stiffness=500, damping=18
     Character: Very fast, pronounced overshoot (~12%), visible
     bounce-settle. Feels playful, energetic, delightful.
     Use SPARINGLY on: toggles, like buttons, notification pops,
     small badges, emoji reactions. NEVER on large elements. */
  --spring-bouncy: linear(
    0, 0.014, 0.055 1.8%, 0.218 3.7%, 0.867 8.5%,
    1.085 10.7%, 1.212 12.9%, 1.264 15.0%, 1.262 17.0%,
    1.217 19.5%, 1.098 24.0%, 1.035 28.5%, 0.993 33.0%,
    0.981 38.0%, 0.988 45.0%, 0.998 55.0%, 1.001 68.0%, 1
  );
  --spring-bouncy-duration: 0.5s;

  /* 4. MATERIAL 3 EMPHASIZED - Google's expressive motion standard
     Source: Material Design 3 motion spec (legacy cubic-bezier fallback)
     Character: Very slow start, dramatic acceleration, gentle decelerate.
     This is the M3 "emphasized" transition for container transforms,
     shared element transitions, and FAB expansions.
     Use on: container morphs, expand/collapse, shared transitions. */
  --m3-emphasized: cubic-bezier(0.05, 0.7, 0.1, 1.0);
  --m3-emphasized-duration: 0.5s;

  /* 5. MATERIAL 3 EMPHASIZED as SPRING - for spring-capable contexts
     Physics: mass=1, stiffness=300, damping=22
     The spring equivalent of M3 Emphasized - with the overshoot
     that Google's spec now recommends via their spring system. */
  --m3-spring: linear(
    0, 0.007, 0.029 2.0%, 0.118 4.2%, 0.508 10.9%,
    0.797 15.4%, 0.951 19.2%, 1.029 22.2%, 1.074 25.6%,
    1.088 29.2%, 1.075 33.6%, 1.045 39.5%, 1.02 46.5%,
    1.007 55.0%, 1.001 66.0%, 1
  );
  --m3-spring-duration: 0.6s;
}

第 2 层级:优质三次贝塞尔曲线——强力回退方案

适用于不支持 linear() 的浏览器,也适用于不宜使用弹簧过冲的次要动画(环境动态、背景过渡、颜色变化)。

:root {
  /* 6. SNAPPY DECEL - Tier 2 fallback for spring-snappy
     The best cubic-bezier approximation of the Apple snappy spring,
     minus the overshoot. Still far better than CSS keyword easings.
     Use when linear() is unavailable, or for secondary reveals. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* 7. SMOOTH IN-OUT - for ambient position shifts
     Neither Material 3 nor Apple style - this is the Awwwards
     agency standard for smooth lateral movements, carousel
     auto-play, and background panning. */
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  /* 8. ENERGETIC SNAP - for hover responses, interactive feedback
     Faster than --ease-out, designed for immediate tactile response.
     The curve front-loads 80% of the motion into the first 30% of
     the duration, creating a "snap" sensation. */
  --ease-snap: cubic-bezier(0.22, 1, 0.36, 1);

  /* 9. DRAMATIC IN-OUT - for hero reveals, cinematic entrances
     Extremely slow start ("winding up"), explosive middle,
     graceful deceleration. Use for the ONE theatrical moment
     per page - the hero heading reveal, a page transition wipe. */
  --ease-dramatic: cubic-bezier(0.77, 0, 0.175, 1);

  /* 10. CUBIC SPRING APPROXIMATION - bouncy without linear()
      The y2 value exceeds 1.0, causing overshoot. This is the
      closest cubic-bezier can get to a spring. Less natural than
      linear() springs but works everywhere. */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

第 3 层级:CSS 关键字缓动——禁止使用

ease、ease-in、ease-out、ease-in-out、linear——这些 CSS 关键字就像字体中的 Comic Sans。它们毫无个性、毫无意图、毫无灵魂。它们存在是因为浏览器需要默认值,而不是因为有设计师主动选择了它们。

CSS 关键字禁止原因替代方案
ease通用曲线,与任何效果都不匹配。等于在说“我没考虑过这个缓动”。--spring-snappy 或 --ease-out
ease-in开始慢、结束快——物体仿佛加速撞向墙壁。几乎从来不是你想要的效果。--ease-dramatic(需要缓慢起步时)
ease-out比 ease 好,但减速效果依然平淡无奇、毫无个性。--spring-snappy 或 --ease-out(自定义曲线)
ease-in-out“我想让它看起来流畅”的默认选项,实际效果却平平无奇。--spring-smooth 或 --ease-in-out(自定义曲线)
linear自然界中的物体不会以恒定速度运动。感觉机械而呆板。仅当用于无限循环(跑马灯、加载动画)的 animation-timing-function 时可接受

⚠ **偏离警告:**如果你在代码库的任何位置写下 transition: all 0.3s ease,就说明实现未达到质量标准。每个过渡都必须使用调色板中的命名曲线。没有例外,也不走捷径。缓动调色板是整个动态体验的 DNA。


→ 三曲线原则(关键)

这是实现协调一致的约束。从上面的 10 条曲线中,每个项目恰好选择 三条——一条主要曲线、一条次要曲线和一条辅助曲线。页面上的每个动画都使用这三条曲线之一,不得例外。同一系列的三条曲线听起来像同一个声音;十条曲线听起来则像委员会的意见。

个性主要(条目、揭示)次要(状态变化、过渡)实用(悬停、反馈、环境动效)
利落--ease-out--ease-in-out--ease-snap
物理感--spring-snappy--spring-smooth--ease-snap
电影感--ease-dramatic--spring-smooth--ease-in-out

这些是推荐的预设。你可以根据项目需求替换其中一种曲线(例如,在趣味性产品中用 --spring-bouncy 替换 --spring-snappy),但总数不得超过三种。如果你发现自己需要第四种曲线,说明前三种中有一种选错了。

→ 如何在 Tier 1 和 Tier 2 之间选择:

动画类型使用此层级原因
首屏入场、页面加载揭示Tier 1(--spring-snappy)第一印象必须有真实的物理感和高级感。
滚动揭示Tier 1(--spring-snappy)用户会看到大量此类效果,每一个都必须鲜活。
按钮/卡片悬停Tier 2(--ease-snap)悬停反馈快速且实用。悬停时弹簧过冲会显得抖动。
按钮点击/激活Tier 1(--spring-bouncy)点击反馈受益于弹簧回弹带来的令人满足的“弹出”效果。
模态框/对话框打开Tier 1(--spring-smooth)模态框具有空间感——它们从某处出现。弹簧能让这种效果显得真实。
标签页切换/轮播Tier 1(--spring-smooth)位置变化需要动量并平稳停下。
背景颜色变化Tier 2(--ease-in-out)颜色没有质量感。颜色变化使用弹簧会显得不协调。
渐变动画Tier 2(--ease-in-out)或 linear环境动效。不需要弹簧。
页面过渡Tier 1(--spring-smooth)页面导航是重要的空间事件,必须有真实的物理感。
工具提示出现Tier 2(--ease-snap)快速、实用、不夸张。
手风琴展开Tier 1(--spring-snappy)或 Tier 1(--m3-spring)高度变化在弹簧平稳停下时显得高级。
浮动/环境动效CSS linear 关键字连续循环无需缓动——匀速才是正确的。

→ Framer Motion / Motion 弹簧等效参数:

/* BLUEPRINT: Framer Motion spring presets matching the CSS palette
   WHY: When using Framer Motion (React), use these spring configs
   instead of the CSS linear() values. Framer Motion's spring()
   computes physics natively, giving even smoother results than
   the CSS approximation. These match the FEEL of the CSS palette. */

const springs = {
  // Matches --spring-snappy: fast, minimal overshoot
  snappy: { type: "spring", stiffness: 400, damping: 30, mass: 1 },

  // Matches --spring-smooth: gentle, visible settle
  smooth: { type: "spring", stiffness: 200, damping: 24, mass: 1 },

  // Matches --spring-bouncy: playful pop
  bouncy: { type: "spring", stiffness: 500, damping: 18, mass: 1 },

  // Matches --m3-spring: Material 3 emphasized
  emphasized: { type: "spring", stiffness: 300, damping: 22, mass: 1 },

  // For hover responses (no spring, just fast decel)
  snap: { type: "tween", duration: 0.35, ease: [0.22, 1, 0.36, 1] },
};

// Usage:
// <motion.div transition={springs.snappy} />
// <motion.div transition={springs.smooth} />

→ GSAP 弹簧等效参数:

/* BLUEPRINT: GSAP spring-like easing
   WHY: GSAP doesn't use spring physics natively, but its
   CustomEase plugin can replicate the feel. For standard use,
   these "power" easings are the closest GSAP equivalents. */

// snappy: "power3.out" or CustomEase
// smooth: "power2.inOut"
// bouncy: "back.out(1.7)"  - the 1.7 controls overshoot amount
// dramatic: "expo.inOut"
// snap: "power4.out"

// For true springs in GSAP, use the gsap-spring plugin:
// gsap.to(".element", { x: 100, ease: "spring({stiffness: 400, damping: 30})" });
→ 动效时间表

按顺序映射每个动画。这就是动效乐谱。

元素触发条件延迟时长缓动变换备注
导航栏页面加载0ms600ms--ease-outopacity 0→1,y -20→0首个出现的元素
Hero 眉题页面加载100ms700ms--ease-outopacity 0→1,y 20→0,blur 8→0错开开始
Hero 标题页面加载200ms800ms--ease-outopacity 0→1,y 30→0,blur 8→0核心视觉焦点
Hero 副文案页面加载320ms700ms--ease-outopacity 0→1,y 20→0标题呈现之后
Hero CTA页面加载440ms600ms--ease-outopacity 0→1,y 20→0,scale 0.95→1最后出现的 Hero 元素
区块标题滚动(可见 20%)0ms800ms--ease-outopacity 0→1,y 40→0每个区块
卡片滚动(可见 15%)0/80/160ms700ms--ease-outopacity 0→1,y 30→0每张卡片依次错开
CTA 按钮悬停0ms500ms--ease-snapy 0→-2px,阴影增强立即响应
卡片悬停0ms400ms--ease-snapy 0→-4px,阴影增强上浮效果

时间规则:

规则数值原因
总入场序列最长时长800ms超过 800ms,页面加载会显得缓慢
错开间隔80-150ms少于 80ms 会感觉同时出现。超过 150ms 会显得迟缓
悬停响应感知到的启动时间 ≤ 150ms用户必须感受到即时反馈
滚动显现时长600-900ms时长足以让人注意到,又不至于造成阻碍
页面过渡300-500ms足够快,不会打断流程;也足够慢,让人感知到
微交互(切换开关、复选框)200-350ms提供功能性反馈,而非戏剧性效果

⚠ 偏差警告: AI 动效最常见的失败是把所有效果都做得太慢。每个区块都用 1.5 秒淡入,会让页面看起来像是在加载,而不是逐步呈现。滚动显现时长应低于 900ms。悬停响应应低于 500ms。页面总入场时长应低于 800ms。

→ 错开编排

错开并非“让每个项目延迟 100ms”。错开应遵循视觉层级。

正确的错开顺序(从上到下 = 从先到后):

1. Container/background (instant or 0ms)
2. Primary content (heading, hero image) - 100ms
3. Supporting content (subtext, description) - 220ms  
4. Interactive elements (CTAs, buttons) - 340ms
5. Decorative elements (badges, accents) - 440ms

网格中的错开(卡片、功能项):

For a 3-column grid, stagger left-to-right:
  Card 1: 0ms
  Card 2: 80ms
  Card 3: 160ms

For a 2x3 grid, stagger top-left to bottom-right:
  Row 1: 0ms, 80ms, 160ms
  Row 2: 120ms, 200ms, 280ms

⚠ 偏差警告: 错开显示的项目不要超过 6-8 个。如果有 12 张卡片,让前 4-6 张依次出现,然后让其余卡片一起出现。12 个项目依次错开需要 1.2 秒以上,用户看着项目一个个出现会失去耐心。

✓ 质量关卡:编排

进入第 3 阶段前,请确认:

  • 已定义缓动方案(未使用 CSS 关键字缓动)
  • 时间表涵盖所有运动元素
  • 没有动画时长超过 900ms
  • 页面总入场时长低于 800ms
  • 错开间隔为 80-150ms
  • 错开顺序遵循视觉层级,而非 DOM 顺序
  • 单独错开显示的项目不超过 6-8 个

第 3 阶段:构建动效(与框架无关的规则)

逐层实现。每一层都基于上一层构建。不要跳过任何层。切勿输出大量样板代码块。 生成实际代码时,请改为应用以下约束:

物理正确性规则

这些规则适用于每个动画,无论其所属层级。违反规则将自动导致质量门禁不通过。

规则规范原因
禁止使用 scale(0)起始值至少为 scale(0.9),并配合 opacity: 0。UI 的范围为 0.9-0.97,微妙入场效果的范围为 0.95-0.97。现实世界中的物体不会凭空出现。scale(0) 看起来像渲染故障,而不是入场效果。
变换原点须与触发位置相对应弹出框、工具提示和下拉菜单应将 transform-origin 设为触发元素的位置。模态框除外——模态框以视口为锚点,而不是以触发元素为锚点,因此应保持 transform-origin: center。元素从其来源位置展开,能营造空间叙事感。从自身中心展开的元素则会显得与触发它的操作脱节。
所有可按压元素都须提供按压反馈每个可按压元素都应使用::active { transform: scale(0.97); transition: transform 160ms var(--ease-snap) }。微妙效果的范围为 0.95-0.98。按下按钮时出现视觉压缩,可以确认界面已响应操作。缺少按压反馈会让 UI 显得反应迟钝,无论实际延迟如何。
禁止使用 transition: all始终指定确切属性:transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out)。transition: all 会对所有发生变化的属性进行动画处理,包括 background-color、box-shadow 和 border,从而导致非 GPU 绘制操作和视觉瑕疵。
采用非对称时长用户有意执行的操作(按下、按住、确认破坏性操作)应较慢。系统响应(松开、关闭、确认)应较快。例如:按下时,按住删除的覆盖层以 2s linear 填充;松开时,以 200ms var(--ease-out) 快速复原。用户决策时放慢动画,能让他们掌控过程。系统响应时加快动画,则能让他们更有信心。时长对称会显得机械。

第 1 层:入场动画(页面加载)

每个首屏元素都需要经过编排后入场。

  • **约束:**根据视觉层级使用交错入场动画(容器 → 标题 → 辅助文本 → CTA → 装饰元素)。
  • **CSS:**使用 @keyframes,将 transform: translateY(24px) 和 filter: blur(6px) 过渡到 0,并应用 --ease-out。通过 animation-delay 设置交错效果。
  • **Framer Motion:**使用 staggerChildren: 0.12。子元素应淡入上移并逐渐清晰。
  • **GSAP:**使用 gsap.timeline() 和 .from() 补间动画。设置 ease: "power3.out"。通过 -=0.5 让补间动画重叠。
第 2 层:滚动触发展示

用户滚动时,首屏以下的元素进入视口后逐步显示。

  • **约束:**不要使用滚动劫持(阻止默认滚动)。应使用与滚动关联的动画(scrub)或由阈值触发的显示效果。
  • **原生 JavaScript:**使用 IntersectionObserver,将阈值设为 0.15,并将 rootMargin 设为 "-50px"。首次触发后取消观察,以避免动画重新播放时出现卡顿。添加 is-visible 类以触发 CSS 过渡。
  • **GSAP:**使用 ScrollTrigger。对于粘性叙事区块,使用 pin: true 和 scrub: 1,让动画进度与滚动位置直接关联。
第 3 层:可中断性规则

可在完成前重新触发的动画(Toast 堆叠、切换、反复操作手风琴、快速悬停)必须妥善处理中断。重新触发时从零开始的动画会造成视觉卡顿。

机制中断时的行为适用场景
CSS transitions从当前值重新设定目标值——在动画进行中反向时依然平滑悬停、切换、手风琴展开/折叠,以及任何快速触发的状态变化
CSS @keyframes从第 0 帧重新开始——会造成跳变只触发一次的单次显示动画(使用 unobserve 的滚动显示)、环境循环动画
CSS @starting-style无需 JS 即可定义入场状态——浏览器会在首次渲染时从起始值过渡无需 useEffect 变通方案的元素入场动画。data-mounted 模式的现代替代方案
WAAPI(element.animate())具备 CSS 线程性能的 JS 控制。硬件加速、可中断,且没有库的额外开销需要 JS 控制时序、同时又要保持 CSS 性能的程序化动画序列
弹簧(Framer Motion / GSAP)中断时保留速度——黄金标准手势驱动的动效、拖拽交互,以及用户可以在动画进行中抓取的任何元素

**500ms 规则:**如果用户可以在 500ms 内两次触发同一个动画(快速点击、来回悬停、Toast 连续弹出),就必须使用 CSS transitions 或弹簧。关键帧动画会卡顿。

第 8 层:状态过渡

实现 UI 状态之间的平滑过渡(模态框、手风琴、标签页)。

  • **模态框:**使用原生 <dialog> 元素。让 ::backdrop 淡入淡出,并对话框本身进行缩放/位移,以营造双层浮起效果。模态框从 scale(0.95) + opacity: 0 开始,绝不使用 scale(0)。设置 transform-origin: center(模态框锚定于视口)。
  • **手风琴:**使用 CSS Grid 将 grid-template-rows 从 0fr 过渡到 1fr,无需 JS 计算即可实现平滑的高度动画。
  • **标签页:**不要仅对活动状态进行交叉淡入淡出。使用滑动指示器(绝对定位的线条),通过 transform: translateX 移动到活动标签页的坐标位置,形成视觉上的连接。
  • **交叉淡入淡出润色:**如果交叉淡入淡出期间两种状态明显重叠(旧内容和新内容都部分可见),在过渡中段添加 filter: blur(2px),让它们融合为一个视觉上的变化。模糊值应低于 16px——强烈模糊会消耗大量 GPU 资源,在 Safari 中尤其明显。
Layer 8.5:手势与拖拽物理效果

对于任何可拖拽、可滑动或可关闭的界面(抽屉、面板、提示消息、卡片、轮播组件):

原则实现方式
基于速度关闭不要要求拖拽距离超过固定阈值。计算速度:Math.abs(dragDistance) / elapsedMs。如果 > 0.11,则无论距离多远都关闭。快速轻扫即可。
动量预测松开时,使用指数衰减预测静止位置:projectedEnd = current + (velocity / 1000) * decayRate / (1 - decayRate),其中 decayRate ≈ 0.998。从预测位置(而不是松开位置)吸附到最近的目标点。
边界处的橡皮筋效果拖过自然边界时(例如,将抽屉拉过最大高度),施加渐进阻力:rubberband(overshoot, dimension, 0.55) = (overshoot * dimension * 0.55) / (dimension + 0.55 * abs(overshoot))。不要硬性停止——元素应像真实物体一样持续减速。
指针捕获在拖拽开始时调用 element.setPointerCapture(e.pointerId)。这样即使指针离开元素边界,也能继续追踪。
多点触控保护拖拽开始后,忽略其他触点:if (isDragging) return。如果不做保护,在拖拽过程中切换手指会导致元素跳到新位置。
速度传递手势结束并开始弹簧动画时,将手指松开时的速度作为弹簧的初始速度。拖拽阶段和回弹动画之间不能有任何视觉断层。
Layer 9:加载与预加载序列
  • **限制:**尽量精简预加载动画。与旋转圆圈相比,带数字计数器的简单扩展线条(scaleX)更显高级。
  • **时机:**切勿强制设置超过 2.5s 的人为最短加载时间。资源(document.fonts.ready、图片)加载完成后,立即(例如通过 clip-path)移除预加载动画,并触发 Layer 1 Hero 入场动画。
第 10 层:标志性微动画

每个页面恰好选择其中 1 到 3 项。克制才能让它们成为标志性设计——如果一切都很特别,那就没有什么特别了。只将它们应用于最值得关注的一个元素(主视觉标题、主要 CTA 或特色视觉效果,不要三者都用)。页面其余部分使用标准的显现效果。正是这种对比,让标志性时刻脱颖而出。

  1. 文字扰乱/解码: 用于主视觉标题或数字。在最终显示真实文本前,先循环显示随机字符(!<>-_\\/[]{}-=+*^?#_)。
  2. 边框描绘: 不要让边框淡入,而是使用伪元素,通过 scaleX/scaleY 将尺寸从 0 缩放到 1,并错开延迟,营造笔尖沿边缘描绘的效果。
  3. 点击涟漪: 在主要按钮上,以 e.clientX / e.clientY(光标位置)为圆心生成一个径向渐变圆,并将其放大至 4x,同时将不透明度渐变至 0。
  4. 闪烁加载: 用于异步数据。使用倾斜角度为 -20deg 的线性渐变,让 background-position 从 200% 移动到 -200%。
  5. 变形 Blob 背景: 用于营造主视觉的纵深感。使用绝对定位的元素,设置 8 个值的 border-radius(例如 60% 40% 30% 70% / 60% 30% 70% 40%),并在约 8 秒内持续动画。
  6. 倾斜视差卡片: 悬停时追踪鼠标位置,根据 data-depth 倍率对内部图层应用轻微的 translate(x,y) 偏移,营造 3D 立体模型效果。
  7. 提示框上浮: 悬停 100ms 后,让提示框从下方浮起。这样光标经过时就不会意外闪现。跳过延迟规则: 同一组中只要已有一个提示框打开,同一工具栏/组内后续提示框就立即打开,且没有延迟和动画。这样整个工具栏会显得反应迅速。
  8. 磁吸光标元素: 当光标进入交互元素的邻近区域(约 40px)时,让元素轻微地向光标移动。使用弹簧插值处理偏移——直接追踪鼠标会显得机械,经过弹簧插值的追踪则更自然。
  9. 渐变边框: 使用 conic-gradient 和 @property --gradient-angle,以线性方式在 3 秒内持续动画,打造流动旋转的边缘。
  10. 光标轨迹: 如果有此需求,使用一个精确追踪光标的小圆点,以及一个稍有延迟、通过轻微线性插值(lerp)跟随的大号空心圆,营造弹性感。触屏设备上隐藏。
  11. 剪切路径显现: 用于主要区块的转场,通过将圆形 clip-path: circle(0% at 50% 50%) 扩展至 150%,显现下一个区块。

第 4 阶段:动画差异检查

将你的动画与动态效果说明和时间表进行比较。逐项检查所有类别。任何一项未通过都不得交付。

⚡ 覆盖检查(强制——首先运行)
检查项通过/失败
页面上的每个标题都有滚动显现或入场动画
每段正文文本至少都有淡入上移动画
每张卡片都有滚动显现动画和悬停状态(上移 + 阴影)
每个按钮都有悬停(上移/擦除/变色)+ 激活(按压)+ 焦点可见状态
每个链接都有悬停下划线动画或颜色变化
每张图片都有显现动画(clip-path、缩放进入或淡入)
每个输入框都有焦点状态(发光、边框变化或标签动画)
每个区块都有滚动触发的入场效果(不能有任何区块只是“静止在那里”)
每个装饰元素都有环境动效(浮动、旋转、脉动)
每条分隔线/线条都会动态显现(scaleX 扩展或淡入)
每个图标都有悬停反馈(颜色、缩放或旋转变化)
滚动进入视野时,统计数字/数值从 0 开始递增
导航栏在页面加载时有入场动画
页脚中的内容会在滚动触发后依次显现
从页面顶部滚动到底部:没有发现任何静态元素

⚠ 如果有任何一项未通过,请返回并补上缺失的动画后再继续。此项不可跳过。动画覆盖率达到 90% 的页面仍会有破绽,破坏高级质感。

观感检查
检查项通过/失败
页面入场总时长不超过 800ms
没有任何元素毫无动画地“突然”出现
依照视觉层级设置错开顺序(标题先于副文本,副文本先于 CTA)
滚动显现应在自然时机触发(元素可见度约为 15-20%)
悬停反馈应立即响应(感知到的启动延迟 ≤ 150ms)
动画不能让人觉得“缓慢”或让用户等待
动画不能让人注意到动画“本身”,而不是内容
**协调性测试:**将页面静音,只感受动效(眯起眼睛)。所有动画是否都像是同一套设计?速度范围、强度和个性是否一致?
**整体效果测试:**即使没有任何单个动画炫技,页面是否仍显得“高级”?目标是做对 20 个不起眼的细节,而不是做一个戏剧化的动画
缓动检查
检查项通过/失败
可见动画中没有使用 CSS 关键字缓动(ease、ease-in、ease-out)
所有入场动画都使用 --ease-out(迅速减速)
所有悬停交互都使用 --ease-snap(活力十足地结束)
所有状态转换都使用 --ease-in-out(平滑)
整个页面的缓动配置保持一致
性能检查
检查项通过/失败
所有动画仅使用 transform 和 opacity(clip-path 显现和 filter:blur 入场除外)
top、left、width、height、margin、padding 上没有动画
任何地方都没有 transition: all——每个 transition 都明确指定具体属性
仅对正在动画的元素应用 will-change
一次性动画完成后移除 will-change
滚动元素上没有使用 backdrop-filter(仅用于 fixed/sticky 元素)
滚动监听器使用 { passive: true }
所有动画期间页面均保持 60fps(通过 DevTools → Performance 检查)
没有布局抖动(循环中先读取布局,再写入布局)
Framer Motion:复杂页面中不使用 x/y/scale 简写属性——为获得 GPU 加速,使用 animate={{ transform: "translateX(100px)" }}
不使用父元素上的 CSS 变量驱动子元素变换(例如 --swipe-amount)——直接在元素上设置 transform,以避免样式重新计算风暴
无障碍检查
检查项通过/失败
所有动态效果均遵循 prefers-reduced-motion: reduce
减少动态效果时的回退方案仅使用不透明度淡入淡出(无变换、无视差、无弹簧过冲)
悬停动画仅在 @media (hover: hover) and (pointer: fine) 下启用——触屏设备会在点击时触发悬停,导致误触
拆分文本包含 aria-label,用于保留原始文本
没有任何关键信息仅通过动画传达
焦点状态清晰可见,且不会被动画遮挡
自动播放的动画(跑马灯、浮动效果、渐变)可以暂停(WCAG 2.2.2)
触屏设备上不会显示自定义光标
技术检查
检查项通过/失败
滚动显现使用 IntersectionObserver,而非滚动事件监听器
滚动联动动画使用 scrub(而非由滚动事件触发)
使用 Lenis 时,触屏设备设置了 smoothTouch: false
未在缺乏明确理由的情况下劫持滚动(覆盖原生滚动行为)
在移动设备上禁用视差(低性能设备上运行不流畅)
在移动设备/触屏设备上禁用自定义光标
预加载器会在最长 3 秒内显示内容
动画初始化前没有 FOUC(无样式内容闪烁)
构图检查
检查项通过/失败
屏幕上同时运行的复杂动画最多为 2-3 个
没有相互争夺注意力的动态效果(两个元素同时抢占注意力)
环境动态效果(浮动、渐变)不会与交互动态效果争夺注意力
动画密度符合动态效果简报(极简/中等/丰富)
**保持个性锁定:**页面上的每个动画都符合锁定的个性(Surgical/Physical/Cinematic)。个性零偏移。
**保持最多三种曲线:**整个页面只使用 3 种缓动曲线。搜索 CSS——如果发现第 4 种曲线,就说明曲线方案失控了。
**保持强度一致:**所有滚动显现都使用相同的变换距离(例如,全部使用 translateY(24px),而不是混用 20/30/40/60)。所有悬停抬升都使用相同的偏移量(例如,全部使用 -4px,而不是混用)。所有交错延迟都使用相同的增量。
标志性微动画最多用于 1-3 个焦点元素,不要散布到各处

反模式

以下是会让高端动态效果显得业余的具体问题。请逐一检查。

❌ 拼凑式动态效果

不同区块使用不同的缓动类型——这里用弹簧,那里用戏剧化曲线,其他地方又用线性急停。每个动画单独看都不错,但整个页面却像拼布。**解决方案:**在阶段 1 锁定一种个性,并严格遵守最多三种曲线的原则。每个动画都必须属于同一缓动类型。如果主视觉使用 --spring-snappy,滚动显现也使用 --spring-snappy。如果卡片悬停使用 --ease-snap,所有交互元素悬停时都使用 --ease-snap。一致性是决定页面看起来“高端”还是“杂乱”的首要因素。

❌ 缓慢显现

所有内容都在 1.5 秒内淡入。页面让人感觉像是在缓冲。**解决方案:**显现动画控制在 800 毫秒以内。用户是来看内容的,不是来看谢幕的。

❌ 滚动嘉年华

每个元素都有不同的动画:这个向左滑入,那个弹跳,这个旋转着出现。**解决方案:**所有滚动显现统一使用一种动画(淡入、上移并去模糊)。一致性会让设计显得有意为之。

❌ 悬停迪斯科

按钮放大到 1.1 倍,卡片旋转,链接闪烁不同颜色。**解决方案:**悬停效果应当含蓄:卡片上移 2px 并扩展阴影,按钮改变背景颜色。不要让用户受到惊吓。

❌ 视差大杂烩

每个区块都有五层视差。前景、中景、背景都以不同速度移动。**解决方案:**每个视口最多使用 2 层视差。一层微妙的背景位移,再加一个浮动元素。更多就会让人晕动。

❌ 标题文字拆分

每个标题都会逐字拆分,并从随机位置重新组合。**修复方法:**每页最多只对一个标题进行逐字拆分。章节标题使用逐词显现效果。其他所有内容都使用简单的向上淡入效果。

❌ 无限预加载器

内容出现前,有一个持续 5 秒、动画繁复的预加载器。**修复方法:**预加载器最长 2.5 秒。如果内容更快加载完成,就提前结束。切勿添加人为延迟。

❌ 缺少减少动态效果支持

任何地方都没有 prefers-reduced-motion 媒体查询。**修复方法:**每个动画都必须通过 prefers-reduced-motion: reduce 进行控制,并提供仅改变透明度的回退效果。

❌ 布局动画器

对 width、height、top、left、padding、margin 或 border-radius 进行动画处理。**修复方法:**只对 transform 和 opacity 进行动画处理。使用 transform: scale() 代替 width/height。使用 transform: translate() 代替 top/left。


框架决策矩阵

如果项目使用……使用此动画技术栈
原生 HTML/CSS/JSCSS 关键帧 + 过渡效果 + IntersectionObserver。只有在需要滚动固定或复杂时间线时才添加 GSAP
React(无框架)Framer Motion(motion/react)。它支持 AnimatePresence、布局动画和手势检测
Next.jsFramer Motion + View Transitions API,用于页面过渡
Vue<Transition> / <TransitionGroup> 组件 + GSAP,用于滚动动画
AstroView Transitions API(内置)+ CSS 动画 + GSAP,用于滚动动画
Svelte内置的 transition: 和 animate: 指令 + GSAP,用于滚动动画

适合使用 GSAP 的场景:

  • 滚动固定(粘滞)序列:内容会随着滚动而变化
  • 水平滚动区块
  • 动画彼此重叠的复杂时间线
  • 使用 SplitText 插件拆分文本(高级付费插件,但同类最佳)

CSS 足以胜任的场景:

  • 入场动画(关键帧 + animation-delay)
  • 悬停状态(过渡效果)
  • 简单的滚动显现效果(IntersectionObserver + CSS 过渡)
  • 浮动/环境动画(关键帧 + 无限循环)
  • 手风琴/标签页状态变化(过渡效果)

Apple 级动效标准

以下是区分 Apple/Awwwards 级动效与其他动效的硬性标准。无论使用何种框架,这些标准都适用。请牢记。

必须使用弹簧物理效果。 每个主要动画(进入、显现、模态框、过渡)都要使用 CSS linear() 弹簧曲线或 Framer Motion 弹簧效果。三次贝塞尔曲线仅适用于次要动效(悬停、颜色变化、环境动效)。如果页面给人的感觉是“数字化”而非“物理化”,说明缓动曲线不对。

Material 3 Expressive 是基准。 Google 的 M3 Expressive 缓动曲线——cubic-bezier(0.05, 0.7, 0.1, 1.0)——是任何过渡效果的最低质量标准。如果你的缓动不如它用心,就替换掉。

每条曲线都经过审慎选择。 同样是 400ms 的动画,使用 ease、cubic-bezier(0.16, 1, 0.3, 1) 和弹簧 linear(),会带来截然不同的情绪感受:平庸、专业、鲜活。你必须能说明选择每条曲线的原因。

错落出现能讲述故事。 元素同时出现是在倾倒数据;元素依次出现才是在讲述故事。错落顺序就是视觉层级。Apple 的错落间隔精确控制在 80-120ms。

动效的关键是克制而有张力。 获奖最多的网站动效更少,而非更多——但每个动效都更加精妙。一个使用弹簧物理效果、带有单词遮罩的文本显现,胜过 20 个平庸的淡入效果。始终以质取胜,而非以量取胜。

性能不容妥协。 45fps 的动画比没有动画更糟糕。只为 transform、opacity 和 filter 添加动画。在 CPU 降频的情况下测试。如果达不到 60fps,就简化动画,直到达到为止。谨慎使用 will-change。

减少动态效果不是可选项。 每个动画都必须受 prefers-reduced-motion 控制。减少动态效果的版本应使用时长更短、仅改变透明度的淡入淡出。不要使用变换、视差、弹簧过冲或与滚动关联的序列。

终极检验。 为你的页面截一张图,把它和 apple.com、linear.app、vercel.com 或 stripe.com 并排放在一起。如果你的动效设计看起来像来自另一个星球,就重新开始。如果看起来像是这些网站中的某个页面,就算通过了。

评论

支持 Markdown