web-animation-design by connorads/dotfiles
npx skills add https://github.com/connorads/dotfiles --skill web-animation-design基于 Emil Kowalski 的 "Animations on the Web" 课程,创建感觉恰到好处的动画的全面指南。
当此技能首次被调用且没有特定问题时,仅回复:
我已准备好根据 Emil Kowalski 的 animations.dev 课程帮助您处理动画问题。
在用户提问之前,不要提供任何其他信息。
审查动画时,必须使用 Markdown 表格。不要使用带有"Before:"和"After:"的列表,并分行显示。始终输出一个实际的 Markdown 表格,如下所示:
| Before | After |
|---|---|
transform: scale(0) | transform: scale(0.95) |
animation: fadeIn 400ms ease-in | animation: fadeIn 200ms ease-out |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| No reduced motion support | @media (prefers-reduced-motion: reduce) {...} |
错误格式(切勿这样做):
Before: transform: scale(0)
After: transform: scale(0.95)
────────────────────────────
Before: 400ms duration
After: 200ms
正确格式:一个包含 | Before | After | 列的单一 Markdown 表格,每个问题占一行。
每个动画决策都始于这些问题:
ease-outease-in-outease用于用户发起的交互:下拉菜单、模态框、工具提示,以及任何进入或退出屏幕的元素。
/* 从弱到强排序 */
--ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
--ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
--ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
--ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
--ease-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1);
为何有效:起始时的加速创造了即时的、响应迅速的感觉。元素"跳向"其目的地,然后平稳停下。
当屏幕上已有的元素需要移动或变形时使用。模拟自然运动,如汽车加速然后刹车。
/* 从弱到强排序 */
--ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
--ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
--ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
--ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
--ease-in-out-expo: cubic-bezier(1, 0, 0, 1);
--ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86);
用于悬停状态和颜色过渡。不对称的曲线(开始快,结束慢)为柔和的动画带来优雅的感觉。
transition: background-color 150ms ease;
仅用于:
对于交互元素,线性动画感觉机械且不自然。
避免用于 UI 动画。 会使界面感觉迟缓,因为缓慢的开始延迟了视觉反馈。
一起动画的元素必须使用相同的缓动和持续时间。模态框 + 遮罩层、工具提示 + 箭头、抽屉 + 背景——如果它们作为一个单元移动,它们就应该感觉像一个单元。
/* 两者使用相同的时序 */
.modal { transition: transform 200ms ease-out; }
.overlay { transition: opacity 200ms ease-out; }
| 元素类型 | 持续时间 |
|---|---|
| 微交互 | 100-150ms |
| 标准 UI(工具提示、下拉菜单) | 150-250ms |
| 模态框、抽屉 | 200-300ms |
| 页面过渡 | 300-400ms |
规则: UI 动画应保持在 300 毫秒以下。较大的元素比较小的元素动画更慢。
确定用户看到动画的频率:
示例: Raycast 从不为其菜单切换按钮添加动画,因为用户每天会打开它数百次。
应该添加动画:
不应该添加动画:
营销与产品:
弹簧动画感觉更自然,因为它们没有固定的持续时间——它们模拟真实的物理效果。
Apple 的方法(推荐):
// 持续时间 + 弹性(更容易理解)
{ type: "spring", duration: 0.5, bounce: 0.2 }
传统物理方法:
// 质量、刚度、阻尼(更复杂)
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }
弹簧动画在被打断时保持速度——CSS 动画从零开始重新启动。这使得弹簧动画非常适合用户可能在运动中途改变的手势。
只对 transform 和 opacity 进行动画处理。这些属性会跳过布局和绘制阶段,完全在 GPU 上运行。
避免对以下属性进行动画处理:
padding、margin、height、width(触发布局)blur 滤镜(开销大,尤其是在 Safari 中)/* 强制 GPU 加速 */
.animated-element {
will-change: transform;
}
React 特定:
Framer Motion:
// 硬件加速(transform 作为字符串)
<motion.div animate={{ transform: "translateX(100px)" }} />
// 非硬件加速(更易读)
<motion.div animate={{ x: 100 }} />
requestAnimationFrame动画可能导致某些用户晕动症或分心。
每当添加动画时,也要添加一个媒体查询来禁用它:
.modal {
animation: fadeIn 200ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
.modal {
animation: none;
}
}
prefers-reduced-motion 媒体查询animation: none 或 transition: none(不使用 !important)import { useReducedMotion } from "framer-motion";
function Component() {
const shouldReduceMotion = useReducedMotion();
return (
<motion.div
initial={shouldReduceMotion ? false : { opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
/>
);
}
/* 在触摸设备上禁用悬停动画 */
@media (hover: hover) and (pointer: fine) {
.element:hover {
transform: scale(1.05);
}
}
触摸设备在点击时会触发悬停,导致误判。
常见场景的快速参考。详细实现请参见 PRACTICAL-TIPS.md。
| 场景 | 解决方案 |
|---|---|
| 让按钮感觉响应迅速 | 在 :active 状态添加 transform: scale(0.97) |
| 元素凭空出现 | 从 scale(0.95) 开始,而不是 scale(0) |
| 动画抖动/卡顿 | 添加 will-change: transform |
| 悬停导致闪烁 | 动画子元素,而不是父元素 |
| 弹出框从错误点缩放 | 将 transform-origin 设置为触发位置 |
| 连续工具提示感觉缓慢 | 在第一个工具提示后跳过延迟/动画 |
| 小按钮难以点击 | 使用 44px 最小点击区域(伪元素) |
| 仍然感觉不对劲 | 添加微妙的模糊(低于 20px)来掩盖它 |
| 悬停在移动设备上触发 | 使用 @media (hover: hover) and (pointer: fine) |
元素是进入还是退出视口? ├── 是 → ease-out └── 否 ├── 它是在屏幕上移动/变形吗? │ └── 是 → ease-in-out └── 是悬停变化吗? ├── 是 → ease └── 是恒定运动吗? ├── 是 → linear └── 默认 → ease-out
每周安装数
88
仓库
GitHub 星标数
7
首次出现
2026年2月9日
安全审计
安装于
gemini-cli85
opencode85
github-copilot84
codex84
cursor83
kimi-cli82
A comprehensive guide for creating animations that feel right, based on Emil Kowalski's "Animations on the Web" course.
When this skill is first invoked without a specific question, respond only with:
I'm ready to help you with animations based on Emil Kowalski's animations.dev course.
Do not provide any other information until the user asks a question.
When reviewing animations, you MUST use a markdown table. Do NOT use a list with "Before:" and "After:" on separate lines. Always output an actual markdown table like this:
| Before | After |
|---|---|
transform: scale(0) | transform: scale(0.95) |
animation: fadeIn 400ms ease-in | animation: fadeIn 200ms ease-out |
| No reduced motion support | @media (prefers-reduced-motion: reduce) {...} |
Wrong format (never do this):
Before: transform: scale(0)
After: transform: scale(0.95)
────────────────────────────
Before: 400ms duration
After: 200ms
Correct format: A single markdown table with | Before | After | columns, one row per issue.
Every animation decision starts with these questions:
ease-outease-in-outeaseUse for user-initiated interactions : dropdowns, modals, tooltips, any element entering or exiting the screen.
/* Sorted weak to strong */
--ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
--ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
--ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
--ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
--ease-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1);
Why it works: Acceleration at the start creates an instant, responsive feeling. The element "jumps" toward its destination then settles in.
Use when elements already on screen need to move or morph. Mimics natural motion like a car accelerating then braking.
/* Sorted weak to strong */
--ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
--ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
--ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
--ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
--ease-in-out-expo: cubic-bezier(1, 0, 0, 1);
--ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86);
Use for hover states and color transitions. The asymmetrical curve (faster start, slower end) feels elegant for gentle animations.
transition: background-color 150ms ease;
Only use for:
Linear feels robotic and unnatural for interactive elements.
Avoid for UI animations. Makes interfaces feel sluggish because the slow start delays visual feedback.
Elements that animate together must use the same easing and duration. Modal + overlay, tooltip + arrow, drawer + backdrop—if they move as a unit, they should feel like a unit.
/* Both use the same timing */
.modal { transition: transform 200ms ease-out; }
.overlay { transition: opacity 200ms ease-out; }
| Element Type | Duration |
|---|---|
| Micro-interactions | 100-150ms |
| Standard UI (tooltips, dropdowns) | 150-250ms |
| Modals, drawers | 200-300ms |
| Page transitions | 300-400ms |
Rule: UI animations should stay under 300ms. Larger elements animate slower than smaller ones.
Determine how often users will see the animation:
Example: Raycast never animates its menu toggle because users open it hundreds of times daily.
Do animate:
Don't animate:
Marketing vs. Product:
Springs feel more natural because they don't have fixed durations—they simulate real physics.
Apple's approach (recommended):
// Duration + bounce (easier to understand)
{ type: "spring", duration: 0.5, bounce: 0.2 }
Traditional physics:
// Mass, stiffness, damping (more complex)
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }
Springs maintain velocity when interrupted—CSS animations restart from zero. This makes springs ideal for gestures users might change mid-motion.
Only animate transform and opacity. These skip layout and paint stages, running entirely on the GPU.
Avoid animating:
padding, margin, height, width (trigger layout)blur filters above 20px (expensive, especially Safari)/* Force GPU acceleration */
.animated-element {
will-change: transform;
}
React-specific:
Framer Motion:
// Hardware accelerated (transform as string)
<motion.div animate={{ transform: "translateX(100px)" }} />
// NOT hardware accelerated (more readable)
<motion.div animate={{ x: 100 }} />
requestAnimationFrameAnimations can cause motion sickness or distraction for some users.
Whenever you add an animation, also add a media query to disable it:
.modal {
animation: fadeIn 200ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
.modal {
animation: none;
}
}
prefers-reduced-motion media queryanimation: none or transition: none (no !important)import { useReducedMotion } from "framer-motion";
function Component() {
const shouldReduceMotion = useReducedMotion();
return (
<motion.div
initial={shouldReduceMotion ? false : { opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
/>
);
}
/* Disable hover animations on touch devices */
@media (hover: hover) and (pointer: fine) {
.element:hover {
transform: scale(1.05);
}
}
Touch devices trigger hover on tap, causing false positives.
Quick reference for common scenarios. See PRACTICAL-TIPS.md for detailed implementations.
| Scenario | Solution |
|---|---|
| Make buttons feel responsive | Add transform: scale(0.97) on :active |
| Element appears from nowhere | Start from scale(0.95), not scale(0) |
| Shaky/jittery animations | Add will-change: transform |
| Hover causes flicker | Animate child element, not parent |
| Popover scales from wrong point | Set transform-origin to trigger location |
Is the element entering or exiting the viewport? ├── Yes → ease-out └── No ├── Is it moving/morphing on screen? │ └── Yes → ease-in-out └── Is it a hover change? ├── Yes → ease └── Is it constant motion? ├── Yes → linear └── Default → ease-out
Weekly Installs
88
Repository
GitHub Stars
7
First Seen
Feb 9, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli85
opencode85
github-copilot84
codex84
cursor83
kimi-cli82
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
116,600 周安装
Web开发最佳实践指南:Lighthouse安全审计、HTTPS、CSP与浏览器兼容性优化
244 周安装
外部研究工具 - 自动化获取文档、最佳实践与API信息 | 2025技术研究助手
244 周安装
React 前端无障碍最佳实践指南:WCAG 标准、语义化 HTML 与键盘导航
245 周安装
GrepAI PostgreSQL存储技能:pgvector扩展实现团队代码搜索与向量数据库集成
249 周安装
four-meme-ai:BSC链上代币创建与交易工具 - 本地化安全操作指南
245 周安装
Go软件架构师技能指南:Golang项目架构决策、设计模式与最佳实践
245 周安装
| Sequential tooltips feel slow |
| Skip delay/animation after first tooltip |
| Small buttons hard to tap | Use 44px minimum hit area (pseudo-element) |
| Something still feels off | Add subtle blur (under 20px) to mask it |
| Hover triggers on mobile | Use @media (hover: hover) and (pointer: fine) |