Stop Animating Everything: A Motion Budget That Respects Users and CPUs
Most product UIs animate too much, too long, and at the wrong easing. Here's the motion budget we use to keep interfaces feeling fast, accessible, and intentional.
Open most B2B dashboards in 2026 and you'll find a card that fades in over 600ms, a sidebar that slides with a bouncy spring, a tooltip that scales from 0.8, and a chart that animates every single bar on every single render. None of it helps the user finish their task. It just makes the product feel slower than it is.
We've spent the last few years tightening motion across client products, and the pattern that keeps working is a motion budget: a small set of rules about what's allowed to move, for how long, and why. Here's how we build one.
Why motion needs a budget
Animation isn't free. Every transform costs frame time, every fade competes with the user's attention, and every spring delays the moment they can click the next thing. The best motion designers we've worked with treat duration the way good writers treat adjectives — suspicious by default.
A motion budget answers three questions before a single keyframe is written:
- What is this animation telling the user? (state change, spatial relationship, feedback, delight)
- How long can it take before it starts feeling slow?
- What happens when the user has
prefers-reduced-motionon, or is on a low-end Android?
If an animation can't answer question one, it shouldn't ship.
The duration ladder
We use a four-rung ladder for durations. It's opinionated, but it survives contact with real products.
| Tier | Duration | Use for |
|---|---|---|
| Instant | 80–120ms | Hover, focus, button press, tooltip show |
| Quick | 160–200ms | Dropdowns, popovers, small state changes |
| Standard | 240–320ms | Modals, drawers, page transitions |
| Deliberate | 400–500ms | Onboarding moments, success celebrations, one-off reveals |
Anything above 500ms in a productivity UI is almost always wrong. If a designer asks for 800ms on a sidebar slide, the honest question is: what is the user looking at for the other 700ms after they already understood the panel opened?
The 2:1 enter/exit ratio
Exits should be roughly half the duration of enters. Users have already processed the element; they don't need another 300ms of fade to say goodbye.
:root {
--motion-quick: 180ms;
--motion-quick-exit: 90ms;
--motion-standard: 280ms;
--motion-standard-exit: 140ms;
}
.dialog[data-state='open'] {
animation: dialog-in var(--motion-standard) var(--ease-out);
}
.dialog[data-state='closed'] {
animation: dialog-out var(--motion-standard-exit) var(--ease-in);
}
This one change alone makes most UIs feel noticeably snappier without anyone being able to articulate why.
Easing: stop using ease-in-out for everything
ease-in-out is the default in most tools, and it's wrong most of the time. It makes things feel sluggish on both ends.
Our working set:
- ease-out (
cubic-bezier(0.2, 0, 0, 1)) — for things entering the screen. Fast start, gentle settle. The element is arriving; the user wants to see it. - ease-in (
cubic-bezier(0.4, 0, 1, 1)) — for things leaving. Quick exit, no lingering. - ease-in-out (
cubic-bezier(0.4, 0, 0.2, 1)) — only for things moving from A to B that stay on screen (a card reordering, a tab indicator sliding). - spring — sparingly. Springs are great for direct manipulation (drag-and-drop release) and terrible for routine state changes.
If you remember one thing: enter with ease-out, exit with ease-in, move with ease-in-out. That covers 90% of product motion.
Tokenise motion like you tokenise color
The same way you wouldn't let a developer hardcode #3b82f6 in a component, you shouldn't let them hardcode transition: all 0.3s ease. Motion belongs in your design tokens.
{
"motion": {
"duration": {
"instant": "100ms",
"quick": "180ms",
"standard": "280ms",
"deliberate": "440ms"
},
"easing": {
"out": "cubic-bezier(0.2, 0, 0, 1)",
"in": "cubic-bezier(0.4, 0, 1, 1)",
"inOut": "cubic-bezier(0.4, 0, 0.2, 1)"
}
}
}
Feed that through Style Dictionary or whatever pipeline you use, and you end up with CSS variables, Tailwind theme values, and Framer Motion presets that all reference the same source of truth. When a designer wants to make the product feel snappier across the board, they change four numbers — not 400 components.
Tailwind config example
// tailwind.config.js
export default {
theme: {
extend: {
transitionDuration: {
instant: '100ms',
quick: '180ms',
standard: '280ms',
deliberate: '440ms',
},
transitionTimingFunction: {
out: 'cubic-bezier(0.2, 0, 0, 1)',
in: 'cubic-bezier(0.4, 0, 1, 1)',
},
},
},
}
Now a developer writes transition-colors duration-quick ease-out and they're inside the system without having to think about it.
Reduced motion is not an opt-out, it's a parallel design
The lazy implementation of prefers-reduced-motion is to set every duration to zero. That technically respects the OS setting and practically makes your app feel broken — modals appear with no indication of where they came from, dropdowns snap into place with no spatial logic.
A better default: keep opacity transitions, remove transforms.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 120ms !important;
}
.motion-transform {
transform: none !important;
}
}
The user still gets a quick fade so they know something changed, but they don't get vestibular-triggering slides, scales, or parallax. This matters more than most teams admit — somewhere between 5% and 15% of users have reduced motion enabled in our analytics across recent projects, with the higher end on accessibility-conscious enterprise clients.
Performance: the 60fps rule has a footnote
Designers think in 60fps. Reality is less generous. On a mid-tier Android in battery saver mode, you're frequently looking at 30fps or worse. Your motion budget needs to assume that.
The practical rules we enforce in code review:
- Only animate
transformandopacity. Animatingwidth,height,top, orbackground-colorforces layout or paint on every frame. - No animations on scroll. If you absolutely must, use
IntersectionObserverto trigger them once, notscrolllisteners running 60 times a second. - Cap simultaneous animations. If a list of 30 items all stagger-fade in, you're not creating delight, you're creating jank. Stagger the first 5–8 visible items and let the rest appear.
will-changeis a loaded gun. Useful for short-lived animations, terrible if left on permanently. Remove it after the animation ends.
Measuring it
Don't trust your MacBook Pro. Run the app on the cheapest Android phone in the office (or use Chrome DevTools' CPU throttling at 4x slowdown) and watch the Performance panel during your hero interactions. If you see a wall of long tasks during a modal open, your motion budget is being overspent.
A short war story
We inherited an e-commerce dashboard last year where the team had built a beautiful animated KPI grid: each card sprung in with a stagger, the numbers counted up over 1.2 seconds, and a subtle glow pulsed every 4 seconds to draw attention. It looked stunning in the demo.
In production, the operations team — the actual users — had set up a browser extension to block animations. They were checking the dashboard 40 times a day and every 1.2-second count-up was 1.2 seconds they didn't have.
We rebuilt it: cards appear instantly, numbers show their final value with a 200ms opacity fade, and the glow was deleted. Task completion time on the primary workflow dropped meaningfully and complaints stopped. Nobody mentioned the lost animations.
Motion has to earn its place. Most of it can't.
Where we'd start
If you're auditing an existing product, do this in order:
- Grep your codebase for hardcoded durations and easings. Every
transition:and every Framer Motiondurationprop. You'll find the spread is wider than you thought. - Define four duration tokens and three easing tokens. That's it. Resist adding more.
- Pick the five most-used interactions (button hover, modal open, dropdown, toast, page transition) and rebuild them on the new tokens with the 2:1 enter/exit ratio.
- Add the reduced-motion media query and actually test it by enabling reduced motion in your OS, not just in DevTools.
- Throttle your CPU to 4x and run through the top three user flows. Anything that drops frames is over budget.
If you want a hand putting this kind of system in place across a design system and a real codebase, that's exactly the kind of work our design and engineering teams do together. Motion is the easiest part of a UI to get wrong and one of the most satisfying to get right.
Want a team like ours?
72Technologies builds production software for the kind of teams who actually read this blog.
Start a projectKeep reading

Hover States Are a Lie on Touch: Designing Interactions That Work on Every Input
Hover is a desktop assumption baked into most component libraries. Here's how to design and build interactions that behave correctly across mouse, touch, stylus, and hybrid devices in 2026.

Dark Mode Isn't a Color Flip: What Actually Breaks When You Ship It
Most dark mode implementations are a broken CSS variable swap held together with hope. Here's what breaks in production — shadows, images, brand color, contrast — and how to build a dark theme that doesn't feel like a bug.
Form Validation Timing: The UX Decision That Breaks Most Sign-up Flows
Validating on every keystroke feels responsive but punishes users mid-thought. Validating only on submit feels rude. Here's the timing model we use to make forms feel calm and competent.
