| 1 | # Motion Design |
| 2 | |
| 3 | ## Duration: The 100/300/500 Rule |
| 4 | |
| 5 | Timing matters more than easing. These durations feel right for most UI: |
| 6 | |
| 7 | | Duration | Use Case | Examples | |
| 8 | |----------|----------|----------| |
| 9 | | **100-150ms** | Instant feedback | Button press, toggle, color change | |
| 10 | | **200-300ms** | State changes | Menu open, tooltip, hover states | |
| 11 | | **300-500ms** | Layout changes | Accordion, modal, drawer | |
| 12 | | **500-800ms** | Entrance animations | Page load, hero reveals | |
| 13 | |
| 14 | **Exit animations are faster than entrances.** Use ~75% of enter duration. |
| 15 | |
| 16 | ## Easing: Pick the Right Curve |
| 17 | |
| 18 | **Don't use `ease`.** It's a compromise that's rarely optimal. Instead: |
| 19 | |
| 20 | | Curve | Use For | CSS | |
| 21 | |-------|---------|-----| |
| 22 | | **ease-out** | Elements entering | `cubic-bezier(0.16, 1, 0.3, 1)` | |
| 23 | | **ease-in** | Elements leaving | `cubic-bezier(0.7, 0, 0.84, 0)` | |
| 24 | | **ease-in-out** | State toggles (there → back) | `cubic-bezier(0.65, 0, 0.35, 1)` | |
| 25 | |
| 26 | **For micro-interactions, use exponential curves.** They feel natural because they mimic real physics (friction, deceleration): |
| 27 | |
| 28 | ```css |
| 29 | /* Quart out - smooth, refined (recommended default) */ |
| 30 | --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); |
| 31 | |
| 32 | /* Quint out - slightly more dramatic */ |
| 33 | --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); |
| 34 | |
| 35 | /* Expo out - snappy, confident */ |
| 36 | --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); |
| 37 | ``` |
| 38 | |
| 39 | **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. |
| 40 | |
| 41 | ## Premium Motion Materials |
| 42 | |
| 43 | 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. |
| 44 | |
| 45 | Use the right material for the effect: |
| 46 | |
| 47 | - **Transform / opacity**: movement, press feedback, simple reveals, list choreography. |
| 48 | - **Blur / filter / backdrop-filter**: focus pulls, depth, glass or lens effects, softened entrances, atmospheric transitions. |
| 49 | - **Clip path / masks**: wipes, reveals, editorial cropping, product-like transitions. |
| 50 | - **Shadow / glow / color filters**: energy, affordance, focus, warmth, active state. |
| 51 | - **Grid-template rows or FLIP-style transforms**: expanding and reflowing layout without animating `height` directly. |
| 52 | |
| 53 | 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. |
| 54 | |
| 55 | ## Staggered Animations |
| 56 | |
| 57 | 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. |
| 58 | |
| 59 | ## Reduced Motion |
| 60 | |
| 61 | This is not optional. Vestibular disorders affect ~35% of adults over 40. |
| 62 | |
| 63 | ```css |
| 64 | /* Define animations normally */ |
| 65 | .card { |
| 66 | animation: slide-up 500ms ease-out; |
| 67 | } |
| 68 | |
| 69 | /* Provide alternative for reduced motion */ |
| 70 | @media (prefers-reduced-motion: reduce) { |
| 71 | .card { |
| 72 | animation: fade-in 200ms ease-out; /* Crossfade instead of motion */ |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | /* Or disable entirely */ |
| 77 | @media (prefers-reduced-motion: reduce) { |
| 78 | *, *::before, *::after { |
| 79 | animation-duration: 0.01ms !important; |
| 80 | transition-duration: 0.01ms !important; |
| 81 | } |
| 82 | } |
| 83 | ``` |
| 84 | |
| 85 | **What to preserve**: Functional animations like progress bars, loading spinners (slowed down), and focus indicators should still work, just without spatial movement. |
| 86 | |
| 87 | ## Perceived Performance |
| 88 | |
| 89 | **Nobody cares how fast your site is, just how fast it feels.** Perception can be as effective as actual performance. |
| 90 | |
| 91 | **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. |
| 92 | |
| 93 | **Active vs passive time**: Passive waiting (staring at a spinner) feels longer than active engagement. Strategies to shift the balance: |
| 94 | |
| 95 | - **Preemptive start**: Begin transitions immediately while loading (iOS app zoom, skeleton UI). Users perceive work happening. |
| 96 | - **Early completion**: Show content progressively, don't wait for everything. Video buffering, progressive images, streaming HTML. |
| 97 | - **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. |
| 98 | |
| 99 | **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. |
| 100 | |
| 101 | **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. |
| 102 | |
| 103 | ## Performance |
| 104 | |
| 105 | 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). |
| 106 | |
| 107 | --- |
| 108 | |
| 109 | **Avoid**: Animating everything (animation fatigue is real). Using >500ms for UI feedback. Ignoring `prefers-reduced-motion`. Using animation to hide slow loading. |
| 110 |