Author: Mike Swanson Machine: DESKTOP-0O8A1RL Timestamp: 2026-05-22 11:07:55
110 lines
5.6 KiB
Markdown
110 lines
5.6 KiB
Markdown
# Motion Design
|
|
|
|
## Duration: The 100/300/500 Rule
|
|
|
|
Timing matters more than easing. These durations feel right for most UI:
|
|
|
|
| Duration | Use Case | Examples |
|
|
|----------|----------|----------|
|
|
| **100-150ms** | Instant feedback | Button press, toggle, color change |
|
|
| **200-300ms** | State changes | Menu open, tooltip, hover states |
|
|
| **300-500ms** | Layout changes | Accordion, modal, drawer |
|
|
| **500-800ms** | Entrance animations | Page load, hero reveals |
|
|
|
|
**Exit animations are faster than entrances.** Use ~75% of enter duration.
|
|
|
|
## Easing: Pick the Right Curve
|
|
|
|
**Don't use `ease`.** It's a compromise that's rarely optimal. Instead:
|
|
|
|
| Curve | Use For | CSS |
|
|
|-------|---------|-----|
|
|
| **ease-out** | Elements entering | `cubic-bezier(0.16, 1, 0.3, 1)` |
|
|
| **ease-in** | Elements leaving | `cubic-bezier(0.7, 0, 0.84, 0)` |
|
|
| **ease-in-out** | State toggles (there → back) | `cubic-bezier(0.65, 0, 0.35, 1)` |
|
|
|
|
**For micro-interactions, use exponential curves.** They feel natural because they mimic real physics (friction, deceleration):
|
|
|
|
```css
|
|
/* Quart out - smooth, refined (recommended default) */
|
|
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
|
|
|
|
/* Quint out - slightly more dramatic */
|
|
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
|
|
|
|
/* Expo out - snappy, confident */
|
|
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
|
|
```
|
|
|
|
**Avoid bounce and elastic curves.** They were trendy in 2015 but now feel tacky and amateurish. Real objects don't bounce when they stop; they decelerate smoothly. Overshoot effects draw attention to the animation itself rather than the content.
|
|
|
|
## Premium Motion Materials
|
|
|
|
Transform and opacity are reliable defaults, not the whole palette. Premium interfaces often need atmospheric properties: blur reveals, backdrop-filter panels, saturation or brightness shifts, shadow bloom, SVG filters, masks, clip paths, gradient-position movement, and variable font or shader-driven effects.
|
|
|
|
Use the right material for the effect:
|
|
|
|
- **Transform / opacity**: movement, press feedback, simple reveals, list choreography.
|
|
- **Blur / filter / backdrop-filter**: focus pulls, depth, glass or lens effects, softened entrances, atmospheric transitions.
|
|
- **Clip path / masks**: wipes, reveals, editorial cropping, product-like transitions.
|
|
- **Shadow / glow / color filters**: energy, affordance, focus, warmth, active state.
|
|
- **Grid-template rows or FLIP-style transforms**: expanding and reflowing layout without animating `height` directly.
|
|
|
|
The hard rule is not "transform and opacity only." The hard rule is: avoid animating layout-driving properties casually (`width`, `height`, `top`, `left`, margins), keep expensive effects bounded to small or isolated areas, and verify in-browser that the result is smooth on the target viewports. If blur/filter makes the interaction feel significantly more premium and remains smooth, use it.
|
|
|
|
## Staggered Animations
|
|
|
|
Use CSS custom properties for cleaner stagger: `animation-delay: calc(var(--i, 0) * 50ms)` with `style="--i: 0"` on each item. **Cap total stagger time**: 10 items at 50ms = 500ms total. For many items, reduce per-item delay or cap staggered count.
|
|
|
|
## Reduced Motion
|
|
|
|
This is not optional. Vestibular disorders affect ~35% of adults over 40.
|
|
|
|
```css
|
|
/* Define animations normally */
|
|
.card {
|
|
animation: slide-up 500ms ease-out;
|
|
}
|
|
|
|
/* Provide alternative for reduced motion */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.card {
|
|
animation: fade-in 200ms ease-out; /* Crossfade instead of motion */
|
|
}
|
|
}
|
|
|
|
/* Or disable entirely */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*, *::before, *::after {
|
|
animation-duration: 0.01ms !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
}
|
|
```
|
|
|
|
**What to preserve**: Functional animations like progress bars, loading spinners (slowed down), and focus indicators should still work, just without spatial movement.
|
|
|
|
## Perceived Performance
|
|
|
|
**Nobody cares how fast your site is, just how fast it feels.** Perception can be as effective as actual performance.
|
|
|
|
**The 80ms threshold**: Our brains buffer sensory input for ~80ms to synchronize perception. Anything under 80ms feels instant and simultaneous. This is your target for micro-interactions.
|
|
|
|
**Active vs passive time**: Passive waiting (staring at a spinner) feels longer than active engagement. Strategies to shift the balance:
|
|
|
|
- **Preemptive start**: Begin transitions immediately while loading (iOS app zoom, skeleton UI). Users perceive work happening.
|
|
- **Early completion**: Show content progressively, don't wait for everything. Video buffering, progressive images, streaming HTML.
|
|
- **Optimistic UI**: Update the interface immediately, handle failures gracefully. Instagram likes work offline; the UI updates instantly, syncs later. Use for low-stakes actions; avoid for payments or destructive operations.
|
|
|
|
**Easing affects perceived duration**: Ease-in (accelerating toward completion) makes tasks feel shorter because the peak-end effect weights final moments heavily. Ease-out feels satisfying for entrances, but ease-in toward a task's end compresses perceived time.
|
|
|
|
**Caution**: Too-fast responses can decrease perceived value. Users may distrust instant results for complex operations (search, analysis). Sometimes a brief delay signals "real work" is happening.
|
|
|
|
## Performance
|
|
|
|
Don't use `will-change` preemptively, only when animation is imminent (`:hover`, `.animating`). For scroll-triggered animations, use Intersection Observer instead of scroll events; unobserve after animating once. Create motion tokens for consistency (durations, easings, common transitions).
|
|
|
|
---
|
|
|
|
**Avoid**: Animating everything (animation fatigue is real). Using >500ms for UI feedback. Ignoring `prefers-reduced-motion`. Using animation to hide slow loading.
|