Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.1 KiB
Web Motion Guidelines
Design and implement web animations that feel natural and purposeful
Timing and Duration
Duration Guidelines
| Element Type | Duration |
|---|---|
| Micro-interactions | 100-150ms |
| Standard UI (tooltips, dropdowns) | 150-250ms |
| Modals, drawers | 200-300ms |
Rules:
- UI animations should stay under 300ms
- Larger elements animate slower than smaller ones
- Exit animations can be ~20% faster than entrance
- Match duration to distance - longer travel = longer duration
The Frequency
Determine how often users will see the animation:
- 100+ times/day → No animation (or drastically reduced)
- Occasional use → Standard animation
- Rare/first-time → Can be more special
Example: Raycast never animates because users open it hundreds of times a day.
When to Animate
Do animate:
- Enter/exit transitions for spatial consistency
- State changes that benefit from visual continuity
- Responses to user actions (feedback)
- Rarely-used interactions where delight adds value
Don't animate:
- Keyboard-initiated actions
- Hover effects on frequently-used elements
- Anything users interact with 100+ times daily
- When speed matters more than smoothness
Performance
Prefer animating transform and opacity. These skip layout and paint stages, running entirely on the GPU.
Avoid animating:
padding,margin,height,width(trigger layout)blurfilters above 20px (expensive, especially Safari)- CSS variables in deep component trees
Optimization Techniques
/* Force GPU acceleration */
.animated-element {
will-change: transform;
}
Practical Tips
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 |
| 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) |
Easing Decision Flowchart
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