ui-animation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUI Animation & Motion Design
UI动画与动态设计
Comprehensive guide for creating purposeful, performant animations in user interfaces.
一份关于在用户界面中创建有意义、高性能动画的综合指南。
Animation Principles
动画原则
The 12 Principles of Animation (Applied to UI)
12项动画原则(UI领域应用)
| Principle | UI Application |
|---|---|
| Timing | Duration reflects importance/distance |
| Easing | Natural acceleration/deceleration |
| Anticipation | Visual preparation for action |
| Follow-through | Momentum continues after stop |
| Secondary Action | Supporting elements respond |
| Staging | Draw attention to key element |
| Squash & Stretch | Bouncy, playful interactions |
| Exaggeration | Emphasize important feedback |
| Arc | Natural curved motion paths |
| Overlap | Elements move at different rates |
| Solid Drawing | Maintain consistent 3D space |
| Appeal | Engaging, delightful motion |
| 原则 | UI场景应用 |
|---|---|
| Timing(时长) | 时长反映操作的重要性或元素移动距离 |
| Easing(缓动) | 模拟自然的加速/减速效果 |
| Anticipation(预备) | 为操作提供视觉准备提示 |
| Follow-through(跟随) | 元素停止后保留动量的余效 |
| Secondary Action(次要动作) | 辅助元素产生联动响应 |
| Staging(聚焦) | 将用户注意力引导至关键元素 |
| Squash & Stretch(挤压与拉伸) | 创造活泼、有趣的交互效果 |
| Exaggeration(夸张) | 强调重要的反馈信息 |
| Arc(弧线运动) | 采用自然的弧形运动路径 |
| Overlap(重叠动画) | 元素以不同速率运动 |
| Solid Drawing(空间一致性) | 保持一致的3D空间感 |
| Appeal(吸引力) | 创造引人入胜、愉悦的动效体验 |
Why Animate?
为什么需要动画?
FUNCTIONAL PURPOSES:
✓ Guide attention to important changes
✓ Show relationships between elements
✓ Provide feedback for actions
✓ Communicate system status
✓ Ease cognitive load
✓ Create spatial orientation
NOT FOR:
✗ Pure decoration
✗ Showing off skills
✗ Making things "feel modern"
✗ Distracting from content功能性用途:
✓ 引导用户关注重要变化
✓ 展示元素间的关联关系
✓ 为用户操作提供反馈
✓ 传达系统状态
✓ 降低认知负担
✓ 构建空间方位感
不适用于:
✗ 纯装饰性场景
✗ 单纯展示技术能力
✗ 只为追求“现代感”
✗ 分散用户对核心内容的注意力Timing & Duration
时长与节奏
Duration Guidelines
时长参考指南
INSTANT (0-100ms):
└─→ Button state changes
└─→ Toggle switches
└─→ Micro-feedback
FAST (100-200ms):
└─→ Hover effects
└─→ Simple fades
└─→ Small movements
STANDARD (200-300ms):
└─→ Most UI transitions
└─→ Modal open/close
└─→ Dropdown menus
SLOW (300-500ms):
└─→ Complex transitions
└─→ Page transitions
└─→ Large element movement
DELIBERATE (500ms+):
└─→ Hero animations
└─→ Skeleton loading
└─→ Onboarding sequences即时(0-100ms):
└─→ 按钮状态切换
└─→ 开关控件切换
└─→ 微型反馈效果
快速(100-200ms):
└─→ 悬停效果
└─→ 简单淡入淡出
└─→ 小范围元素移动
标准(200-300ms):
└─→ 大多数UI过渡效果
└─→ 模态框打开/关闭
└─→ 下拉菜单展开/收起
缓慢(300-500ms):
└─→ 复杂过渡效果
└─→ 页面切换
└─→ 大范围元素移动
刻意延迟(500ms以上):
└─→ 首屏英雄区动画
└─→ 骨架屏加载
└─→ 新手引导流程Distance-Based Timing
基于距离的时长计算
Rule: Longer distance = Longer duration
Small (< 100px): 150-200ms
Medium (100-300px): 200-300ms
Large (300-500px): 300-400ms
Full screen: 400-500ms
Formula:
duration = baseTime + (distance × factor)规则:移动距离越长,动画时长越久
小距离(< 100px): 150-200ms
中距离(100-300px):200-300ms
大距离(300-500px):300-400ms
全屏移动: 400-500ms
计算公式:
duration = baseTime + (distance × factor)Easing Functions
缓动函数
Standard Easings
标准缓动类型
LINEAR
├────────────────────────────┤
Constant speed. Rarely natural.
Use: Progress bars, clock hands
EASE-OUT (Deceleration)
├═══════════────────────────┤
Fast start, slow end.
Use: Elements entering the screen
EASE-IN (Acceleration)
├────────────────═══════════┤
Slow start, fast end.
Use: Elements leaving the screen
EASE-IN-OUT (S-curve)
├────═══════════════────────┤
Slow start and end, fast middle.
Use: On-screen transitions
EASE-OUT-BACK (Overshoot)
├═══════════────────────╗───┤
Overshoots, settles back.
Use: Playful entrances, bouncesLINEAR(线性)
├────────────────────────────┤
匀速运动,很少符合自然规律。
适用场景:进度条、时钟指针
EASE-OUT(减速)
├═══════════────────────────┤
快速启动,缓慢结束。
适用场景:元素进入屏幕
EASE-IN(加速)
├────────────────═══════════┤
缓慢启动,快速结束。
适用场景:元素离开屏幕
EASE-IN-OUT(S曲线)
├────═══════════════────────┤
缓慢启动和结束,中间快速运动。
适用场景:屏幕内元素状态过渡
EASE-OUT-BACK(回弹)
├═══════════────────────╗───┤
元素超出目标位置后回弹复位。
适用场景:活泼的入场动画、弹跳效果CSS Easing Values
CSS缓动值
css
/* Built-in keywords */
linear: cubic-bezier(0, 0, 1, 1)
ease: cubic-bezier(0.25, 0.1, 0.25, 1)
ease-in: cubic-bezier(0.42, 0, 1, 1)
ease-out: cubic-bezier(0, 0, 0.58, 1)
ease-in-out: cubic-bezier(0.42, 0, 0.58, 1)
/* Material Design standard */
standard: cubic-bezier(0.4, 0, 0.2, 1)
decelerate: cubic-bezier(0, 0, 0.2, 1)
accelerate: cubic-bezier(0.4, 0, 1, 1)
/* Custom: Snappy */
snappy: cubic-bezier(0.5, 0, 0, 1)
/* Custom: Bouncy */
bouncy: cubic-bezier(0.68, -0.55, 0.27, 1.55)
/* Spring-like (use JS libraries) */
spring: { stiffness: 300, damping: 20 }css
/* 内置关键字 */
linear: cubic-bezier(0, 0, 1, 1)
ease: cubic-bezier(0.25, 0.1, 0.25, 1)
ease-in: cubic-bezier(0.42, 0, 1, 1)
ease-out: cubic-bezier(0, 0, 0.58, 1)
ease-in-out: cubic-bezier(0.42, 0, 0.58, 1)
/* Material Design标准 */
standard: cubic-bezier(0.4, 0, 0.2, 1)
decelerate: cubic-bezier(0, 0, 0.2, 1)
accelerate: cubic-bezier(0.4, 0, 1, 1)
/* 自定义:敏捷型 */
snappy: cubic-bezier(0.5, 0, 0, 1)
/* 自定义:弹跳型 */
bouncy: cubic-bezier(0.68, -0.55, 0.27, 1.55)
/* 弹簧效果(需使用JS库) */
spring: { stiffness: 300, damping: 20 }When to Use Each
场景适配建议
| Scenario | Easing | Why |
|---|---|---|
| Element entering | ease-out | Arrives energetically, settles |
| Element leaving | ease-in | Gathers momentum to exit |
| On-screen change | ease-in-out | Smooth state change |
| Attention grabbing | bounce/spring | Playful, noticeable |
| Background/subtle | ease-out | Unobtrusive |
| 场景 | 缓动类型 | 原因说明 |
|---|---|---|
| 元素入场 | ease-out | 充满活力地到达目标位置后平稳过渡 |
| 元素离场 | ease-in | 逐渐积累动量后离开屏幕 |
| 屏幕内状态变化 | ease-in-out | 平滑的状态切换体验 |
| 需要吸引注意力 | bounce/spring | 活泼醒目,容易引起关注 |
| 背景/细微效果 | ease-out | 不干扰用户核心操作 |
Animation Patterns
动画模式
Micro-interactions
微交互
BUTTON STATES:
┌─────────────────────────────────────────┐
│ Rest → Hover: scale(1.02), 100ms │
│ Hover → Active: scale(0.98), 50ms │
│ Active → Rest: scale(1), 150ms ease-out │
└─────────────────────────────────────────┘
TOGGLE SWITCH:
┌─────────────────────────────────────────┐
│ Thumb: translateX, 200ms ease-out │
│ Track: background-color, 200ms │
│ State: slight bounce at end │
└─────────────────────────────────────────┘
CHECKBOX:
┌─────────────────────────────────────────┐
│ Check mark: stroke-dashoffset animation │
│ Background: scale from center, 150ms │
│ Ripple: expanding circle, 300ms │
└─────────────────────────────────────────┘按钮状态变化:
┌─────────────────────────────────────────┐
│ 常态 → 悬停:scale(1.02),100ms │
│ 悬停 → 激活:scale(0.98),50ms │
│ 激活 → 常态:scale(1),150ms ease-out │
└─────────────────────────────────────────┘
开关控件:
┌─────────────────────────────────────────┐
│ 滑块:translateX,200ms ease-out │
│ 轨道:background-color,200ms │
│ 状态切换:结束时轻微回弹 │
└─────────────────────────────────────────┘
复选框:
┌─────────────────────────────────────────┐
│ 勾选标记:stroke-dashoffset动画效果 │
│ 背景:从中心缩放,150ms │
│ 波纹:扩散圆形效果,300ms │
└─────────────────────────────────────────┘Loading States
加载状态
SKELETON SCREENS:
┌──────────────────────────┐
│ ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░ │ Shimmer effect
│ ▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░ │ Linear gradient
│ ▓▓▓▓▓▓░░░░░░░░░░░░░░░░ │ Moving left to right
└──────────────────────────┘
CSS:
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e0e0e0 50%,
#f0f0f0 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
SPINNER:
- Duration: 1-2 seconds per rotation
- Easing: linear (consistent motion)
- Style: Match brand identity骨架屏:
┌──────────────────────────┐
│ ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░ │ 微光效果
│ ▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░ │ 线性渐变
│ ▓▓▓▓▓▓░░░░░░░░░░░░░░░░ │ 从左向右移动
└──────────────────────────┘
CSS代码:
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e0e0e0 50%,
#f0f0f0 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
加载旋转器:
- 时长:每旋转1-2秒
- 缓动:linear(匀速运动)
- 风格:匹配品牌视觉Page Transitions
页面过渡
CROSSFADE:
├──────────────────────────────────────────┤
│ Old page: opacity 1 → 0, 200ms │
│ New page: opacity 0 → 1, 200ms │
│ Timing: Sequential or overlapping │
└──────────────────────────────────────────┘
SLIDE:
├──────────────────────────────────────────┤
│ Direction follows navigation hierarchy │
│ Forward: Slide left (new from right) │
│ Back: Slide right (prev from left) │
│ Duration: 300-400ms │
└──────────────────────────────────────────┘
SHARED ELEMENT:
├──────────────────────────────────────────┤
│ Element morphs between states │
│ Position, size, border-radius change │
│ Creates continuity between screens │
│ Duration: 300-500ms │
└──────────────────────────────────────────┘交叉淡入淡出:
├──────────────────────────────────────────┤
│ 旧页面:opacity从1→0,200ms │
│ 新页面:opacity从0→1,200ms │
│ 时序:可顺序执行或重叠执行 │
└──────────────────────────────────────────┘
滑动过渡:
├──────────────────────────────────────────┤
│ 方向遵循导航层级逻辑 │
│ 前进:向左滑动(新页面从右侧进入) │
│ 返回:向右滑动(上一页从左侧进入) │
│ 时长:300-400ms │
└──────────────────────────────────────────┘
共享元素过渡:
├──────────────────────────────────────────┤
│ 元素在不同状态间变形过渡 │
│ 位置、尺寸、圆角属性变化 │
│ 在不同页面间创造视觉连续性 │
│ 时长:300-500ms │
└──────────────────────────────────────────┘List Animations
列表动画
STAGGERED ENTRANCE:
┌─ Item 1 ────────────────┐ delay: 0ms
├─ Item 2 ────────────────┤ delay: 50ms
├─ Item 3 ────────────────┤ delay: 100ms
├─ Item 4 ────────────────┤ delay: 150ms
└─ Item 5 ────────────────┘ delay: 200ms
Max total duration: 500ms
Stagger: 30-50ms per item
Animation: translateY + opacity
REORDER:
- Use FLIP technique
- Duration: 200-300ms
- Ease: ease-out stagger入场:
┌─ 项1 ────────────────┐ 延迟:0ms
├─ 项2 ────────────────┤ 延迟:50ms
├─ 项3 ────────────────┤ 延迟:100ms
├─ 项4 ────────────────┤ 延迟:150ms
└─ 项5 ────────────────┘ 延迟:200ms
总时长上限:500ms
stagger间隔:30-50ms每一项
动画效果:translateY + opacity
重排动画:
- 使用FLIP技术
- 时长:200-300ms
- 缓动:ease-outPerformance
性能优化
GPU-Accelerated Properties
GPU加速属性
FAST (Compositor only):
✓ transform: translate, scale, rotate
✓ opacity
✓ filter (with will-change)
SLOW (Triggers layout/paint):
✗ width, height
✗ margin, padding
✗ top, left, right, bottom
✗ border, border-radius
✗ font-size
✗ box-shadow (repaints)
OPTIMIZATION:
will-change: transform, opacity;
/* Use sparingly! */高效(仅需合成器处理):
✓ transform: translate、scale、rotate
✓ opacity
✓ filter(配合will-change)
低效(触发布局/重绘):
✗ width、height
✗ margin、padding
✗ top、left、right、bottom
✗ border、border-radius
✗ font-size
✗ box-shadow(导致重绘)
优化技巧:
will-change: transform, opacity;
/* 请谨慎使用! */Performance Guidelines
性能优化指南
css
/* Good: GPU-accelerated */
.animated-element {
transform: translateX(0);
transition: transform 300ms ease-out;
}
.animated-element.moved {
transform: translateX(100px);
}
/* Bad: Layout thrashing */
.animated-element {
left: 0;
transition: left 300ms ease-out;
}
.animated-element.moved {
left: 100px;
}css
/* 推荐:GPU加速 */
.animated-element {
transform: translateX(0);
transition: transform 300ms ease-out;
}
.animated-element.moved {
transform: translateX(100px);
}
/* 不推荐:布局抖动 */
.animated-element {
left: 0;
transition: left 300ms ease-out;
}
.animated-element.moved {
left: 100px;
}FLIP Technique
FLIP技术
javascript
// First: Get initial position
const first = element.getBoundingClientRect();
// Last: Apply change, get final position
element.classList.add("moved");
const last = element.getBoundingClientRect();
// Invert: Calculate delta, apply inverse transform
const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
element.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
// Play: Remove transform with transition
requestAnimationFrame(() => {
element.style.transition = "transform 300ms ease-out";
element.style.transform = "";
});javascript
// First:获取元素初始位置
const first = element.getBoundingClientRect();
// Last:应用变化,获取最终位置
element.classList.add("moved");
const last = element.getBoundingClientRect();
// Invert:计算偏移量,应用反向变换
const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
element.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
// Play:移除变换并应用过渡效果
requestAnimationFrame(() => {
element.style.transition = "transform 300ms ease-out";
element.style.transform = "";
});CSS Animation Techniques
CSS动画技巧
Keyframe Animation
关键帧动画
css
@keyframes fadeSlideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.element {
animation: fadeSlideIn 300ms ease-out forwards;
}
/* With steps */
@keyframes typewriter {
from {
width: 0;
}
to {
width: 100%;
}
}
.typing-text {
animation: typewriter 2s steps(20) forwards;
}css
@keyframes fadeSlideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.element {
animation: fadeSlideIn 300ms ease-out forwards;
}
/* 逐帧动画 */
@keyframes typewriter {
from {
width: 0;
}
to {
width: 100%;
}
}
.typing-text {
animation: typewriter 2s steps(20) forwards;
}Transition
过渡动画
css
.button {
background: var(--primary);
transform: scale(1);
transition:
background 150ms ease-out,
transform 100ms ease-out;
}
.button:hover {
background: var(--primary-hover);
transform: scale(1.02);
}
.button:active {
transform: scale(0.98);
transition-duration: 50ms;
}css
.button {
background: var(--primary);
transform: scale(1);
transition:
background 150ms ease-out,
transform 100ms ease-out;
}
.button:hover {
background: var(--primary-hover);
transform: scale(1.02);
}
.button:active {
transform: scale(0.98);
transition-duration: 50ms;
}Animation Shorthand
动画简写语法
css
/* animation: name duration timing-function delay
iteration-count direction fill-mode play-state */
animation: slideIn 300ms ease-out 100ms 1 normal forwards running;
/* Common patterns */
animation: spin 1s linear infinite;
animation: pulse 2s ease-in-out infinite alternate;
animation: fadeIn 300ms ease-out forwards;css
/* animation: 名称 时长 缓动函数 延迟
迭代次数 方向 填充模式 播放状态 */
animation: slideIn 300ms ease-out 100ms 1 normal forwards running;
/* 常见模式 */
animation: spin 1s linear infinite;
animation: pulse 2s ease-in-out infinite alternate;
animation: fadeIn 300ms ease-out forwards;JavaScript Animation Libraries
JavaScript动画库
Comparison
库对比
| Library | Best For | Bundle Size |
|---|---|---|
| CSS | Simple transitions | 0kb |
| Web Animations API | Native, performant | 0kb |
| GSAP | Complex, precise | ~60kb |
| Framer Motion | React ecosystem | ~50kb |
| anime.js | Timeline, SVG | ~17kb |
| Motion One | Modern, lightweight | ~18kb |
| Lottie | After Effects export | ~50kb |
| 库名称 | 最佳适用场景 | 包大小 |
|---|---|---|
| CSS | 简单过渡效果 | 0kb |
| Web Animations API | 原生高性能动画 | 0kb |
| GSAP | 复杂高精度动画 | ~60kb |
| Framer Motion | React生态系统 | ~50kb |
| anime.js | 时间轴动画、SVG动画 | ~17kb |
| Motion One | 现代轻量级动画 | ~18kb |
| Lottie | After Effects导出动画 | ~50kb |
Framer Motion (React)
Framer Motion(React)
jsx
import { motion, AnimatePresence } from "framer-motion";
// Basic animation
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3, ease: "easeOut" }}
>
Content
</motion.div>;
// Variants for complex animations
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
};
<motion.ul variants={containerVariants} initial="hidden" animate="visible">
{items.map((item) => (
<motion.li key={item.id} variants={itemVariants}>
{item.name}
</motion.li>
))}
</motion.ul>;jsx
import { motion, AnimatePresence } from "framer-motion";
// 基础动画
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3, ease: "easeOut" }}
>
内容
</motion.div>;
// 复杂动画变体
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
};
<motion.ul variants={containerVariants} initial="hidden" animate="visible">
{items.map((item) => (
<motion.li key={item.id} variants={itemVariants}>
{item.name}
</motion.li>
))}
</motion.ul>;GSAP
GSAP
javascript
import { gsap } from "gsap";
// Basic tween
gsap.to(".element", {
x: 100,
opacity: 1,
duration: 0.3,
ease: "power2.out",
});
// Timeline
const tl = gsap.timeline();
tl.from(".header", { y: -100, duration: 0.5 })
.from(".content", { opacity: 0, duration: 0.3 }, "-=0.2")
.from(".button", { scale: 0.8, duration: 0.2 });
// ScrollTrigger
gsap.registerPlugin(ScrollTrigger);
gsap.to(".parallax", {
y: -100,
scrollTrigger: {
trigger: ".section",
start: "top center",
end: "bottom center",
scrub: true,
},
});javascript
import { gsap } from "gsap";
// 基础补间动画
gsap.to(".element", {
x: 100,
opacity: 1,
duration: 0.3,
ease: "power2.out",
});
// 时间轴动画
const tl = gsap.timeline();
tl.from(".header", { y: -100, duration: 0.5 })
.from(".content", { opacity: 0, duration: 0.3 }, "-=0.2")
.from(".button", { scale: 0.8, duration: 0.2 });
// 滚动触发动画
gsap.registerPlugin(ScrollTrigger);
gsap.to(".parallax", {
y: -100,
scrollTrigger: {
trigger: ".section",
start: "top center",
end: "bottom center",
scrub: true,
},
});Accessibility
无障碍设计
Respecting User Preferences
尊重用户偏好
css
/* Reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Or provide simpler alternatives */
@media (prefers-reduced-motion: reduce) {
.animated-element {
/* Replace motion with opacity */
animation: none;
transition: opacity 200ms ease;
}
}css
/* 为偏好减少动画的用户优化 */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 或提供更简单的替代方案 */
@media (prefers-reduced-motion: reduce) {
.animated-element {
/* 用透明度变化替代动效 */
animation: none;
transition: opacity 200ms ease;
}
}Safe Animation Practices
安全动画实践
AVOID for vestibular disorders:
✗ Parallax scrolling effects
✗ Zooming/scaling animations
✗ Spinning/rotating elements
✗ Auto-playing animations
✗ Flashing (>3 times/second)
SAFE alternatives:
✓ Opacity fades
✓ Color transitions
✓ Subtle position changes
✓ User-initiated animations前庭障碍用户需避免:
✗ 视差滚动效果
✗ 缩放动画
✗ 旋转/自旋元素
✗ 自动播放动画
✗ 高频闪烁(>3次/秒)
安全替代方案:
✓ 透明度淡入淡出
✓ 颜色过渡
✓ 细微位置变化
✓ 用户触发的动画WCAG Guidelines
WCAG指南
2.2.2 Pause, Stop, Hide:
- Auto-updating content can be paused
- No time limits on reading
2.3.1 Three Flashes:
- Nothing flashes more than 3x per second
2.3.3 Animation from Interactions:
- Motion can be disabled
- Triggered animations respect preferences2.2.2 暂停、停止、隐藏:
- 自动更新的内容可暂停
- 阅读内容无时间限制
2.3.1 三次闪烁限制:
- 任何元素闪烁频率不超过3次/秒
2.3.3 交互触发动画:
- 动效可被禁用
- 触发的动画尊重用户偏好Mobile Considerations
移动端适配
Touch Feedback
触摸反馈
css
/* iOS-style tap feedback */
.button {
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.button:active {
opacity: 0.7;
transition: opacity 50ms;
}
/* Ripple effect */
.ripple {
position: relative;
overflow: hidden;
}
.ripple::after {
content: "";
position: absolute;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: scale(0);
animation: ripple 400ms ease-out;
}css
/* iOS风格点击反馈 */
.button {
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.button:active {
opacity: 0.7;
transition: opacity 50ms;
}
/* 波纹效果 */
.ripple {
position: relative;
overflow: hidden;
}
.ripple::after {
content: "";
position: absolute;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: scale(0);
animation: ripple 400ms ease-out;
}Platform Conventions
平台设计规范
| Platform | Animation Style |
|---|---|
| iOS | Spring physics, 300-500ms, subtle |
| Android | Material motion, 200-300ms, emphasized |
| Web | Varies, typically 200-400ms |
| 平台 | 动画风格 |
|---|---|
| iOS | 弹簧物理效果,300-500ms,风格细腻 |
| Android | Material Design动效,200-300ms,强调交互 |
| Web | 风格多样,通常200-400ms |
Design System Integration
设计系统集成
Animation Tokens
动画令牌
css
:root {
/* Durations */
--duration-instant: 100ms;
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
--duration-slower: 600ms;
/* Easings */
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-bounce: cubic-bezier(0.68, -0.55, 0.27, 1.55);
/* Combined */
--transition-default: var(--duration-normal) var(--ease-default);
--transition-fast: var(--duration-fast) var(--ease-out);
}
/* Usage */
.element {
transition: transform var(--transition-default);
}css
:root {
/* 时长令牌 */
--duration-instant: 100ms;
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
--duration-slower: 600ms;
/* 缓动令牌 */
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-bounce: cubic-bezier(0.68, -0.55, 0.27, 1.55);
/* 组合令牌 */
--transition-default: var(--duration-normal) var(--ease-default);
--transition-fast: var(--duration-fast) var(--ease-out);
}
/* 使用示例 */
.element {
transition: transform var(--transition-default);
}Best Practices
最佳实践
DO:
建议遵循:
- Animate with purpose (feedback, guidance)
- Use GPU-accelerated properties
- Keep durations under 500ms
- Match animation to brand personality
- Respect prefers-reduced-motion
- Test on low-end devices
- Use consistent timing system
- 动画需具备明确目的(反馈、引导等)
- 使用GPU加速属性
- 动画时长控制在500ms以内
- 动画风格匹配品牌调性
- 尊重用户的减少动效偏好
- 在低端设备上测试
- 使用统一的时长系统
DON'T:
建议避免:
- Animate for decoration alone
- Block user interaction
- Use excessive bounce/overshoot
- Create motion sickness triggers
- Forget exit animations
- Ignore performance metrics
- Delay essential content
- 仅为装饰添加动画
- 动画阻塞用户交互
- 过度使用弹跳/回弹效果
- 可能引发晕动症的动效
- 忽略退出动画
- 无视性能指标
- 延迟核心内容加载
Animation Checklist
动画检查清单
Pre-Implementation
实现前:
- Animation serves a purpose
- Duration appropriate for action
- Easing matches motion intent
- Performance impact assessed
- 动画具备明确的功能性目的
- 时长与操作场景匹配
- 缓动类型符合动效意图
- 已评估性能影响
Implementation
实现中:
- Uses GPU-accelerated properties
- prefers-reduced-motion respected
- Works on target devices
- No layout thrashing
- 使用GPU加速属性
- 已适配prefers-reduced-motion
- 在目标设备上可正常运行
- 无布局抖动问题
Quality Check
质量检查:
- Feels natural and responsive
- Doesn't delay user
- Consistent with design system
- Accessible to all users
- 动效自然且响应迅速
- 不干扰用户操作
- 与设计系统保持一致
- 对所有用户无障碍