Most engineers set transition: all 0.3s ease and move on. That’s why their UIs feel mechanical. The duration barely matters; the easing curve is what your eye reads as natural or fake. Get the curve right and the rest falls into place.
Easing beats duration
ease and linear are the two curves you should almost never use.linear reads as robotic because nothing in the physical world moves at a constant speed — real motion accelerates and decelerates. Reach for ease-out as your default. It covers about 90% of interface motion. Save a custom cubic-bezier for when you can say out loud why the default feels wrong.
Ease-out for entrances
When something enters — a modal, a toast, a menu — it should decelerate into place with ease-out. It arrives fast, then settles, which reads as confident. When something leaves, use ease-in: it starts slow and accelerates away, so exits feel final and don’t linger. Then match duration to distance, not to a fixed number. A tooltip travelling 8px wants roughly 120ms; a panel crossing the screen wants around 300ms. Same curve, different time.
Springs for gestures
CSS timing functions are perfect for taps and state changes. But the moment a user is dragging — a sheet, a swipe-to-dismiss, a slider — switch to a spring. A spring has no fixed duration; it responds to velocity, so when someone flicks fast the animation moves fast. That’s the trick behind why iOS feels alive. In React, Framer Motion’s spring transitions do this for free: give them a stiffness and damping and skip hand-tuned keyframes entirely.
Always respect reduced motion
None of this ships without one guard: prefers-reduced-motion. A real slice of your users get nauseous from motion, and the OS already knows their preference. When reduce is set, drop transforms and large movements to a near-instant fade or to nothing. Keep the feedback, cut the travel.