# Easing curves

> Pick the right easing curve for anything that moves, and know why ease-out makes the same animation feel faster.

Module: Motion · Level: beginner · 7 min · https://school.agents.org.in/design/motion/easing

Open both dropdowns at once. They take exactly the same 250 milliseconds. One of them feels sluggish.

*[Interactive demo: Same menu, same duration. Only the curve differs. Try slow-mo to see why.]*

The difference is the easing (How speed changes during an animation: start fast and slow down, start slow and speed up, or both. It decides whether motion feels snappy or sluggish): how the speed changes during the animation. The left one uses ease-in (An easing that starts slowly and speeds up toward the end. It makes UI feel sluggish because nothing happens right when you're watching, so avoid it in interfaces), which starts slowly and speeds up. The right one uses ease-out (An easing that moves fast at the start and slows into the end. The right default for anything entering or leaving, because it reacts the moment you act), which moves most of the way at once and spends the rest of its time settling.

When you click, your eye goes straight to where the menu should appear. Ease-out puts something there in the very first frames. Ease-in makes you watch almost nothing happen, right at the moment you're paying the most attention. **Never use ease-in on UI, exits included.**

## The decision order

You don't need to memorise curves. You need one rule per situation:

| What's happening | Curve |
|---|---|
| Something entering or leaving (menu, toast, modal) | ease-out |
| Something already on screen moving from A to B (a tab indicator) | ease-in-out |
| A hover or a color change | `ease` |
| Constant motion: a progress bar, a marquee, a hold-to-confirm fill | `linear` |
| Not sure | ease-out |

A drag, a flick or anything your finger is steering doesn't use a curve at all. It uses a spring, which gets its own lesson.

## Custom curves beat the built-ins

CSS ships `ease`, `ease-in`, `ease-out` and `ease-in-out`. They were fine defaults a decade ago; today they read as "nobody chose this". A cubic-bezier (A way to write your own easing curve as four numbers, like cubic-bezier(0.23, 1, 0.32, 1). Custom curves feel more deliberate than the built-in ones) lets you write your own curve as four numbers, and a slightly stronger curve is most of what makes motion feel deliberate.

*[Interactive demo: Pick a curve to see its shape and watch the ball run it. The red one is the one to avoid.]*

Here is a small set worth keeping as tokens, mostly from Emil Kowalski's practice:

```css
:root {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);        /* menus, popovers, toasts, modals */
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);    /* on-screen travel, tab indicators */
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);     /* sheets and drawers from an edge */
  --ease-out-soft: cubic-bezier(0.25, 1, 0.5, 1);    /* gentler hovers and menus */
  --ease-back: cubic-bezier(0.34, 1.56, 0.64, 1);    /* overshoots: playful moments only */
}
```

Read the curve like a graph: time runs left to right, progress bottom to top. A steep start means it moves early. A number above 1 (like the `1.56` in back-out) means it shoots past the end and settles back, which is cute on a sticker and wrong on a delete dialog.

> **In plain words.** ease-out = fast then gentle. ease-in = gentle then fast. For anything a person just asked for, fast first.

## Curve and duration go together

A beautiful curve on the wrong duration looks worse than a plain ease-out on the right one. Tune them as a pair, which is the next lesson. Need a curve that isn't on the list? Take one from easing.dev or easings.co rather than hand-rolling four numbers.

  **Before (avoid):**

```css
.menu {
  transition: all 300ms ease-in;
}
```

  **After (do this):**

```css
.menu {
  transition:
    opacity 200ms var(--ease-out),
    transform 200ms var(--ease-out);
}
```

Three fixes in one line: ease-out instead of ease-in, a named list of properties instead of `all`, and a shorter duration.

## A note on writing it down

Small conventions make motion CSS easier to read and review. They come from Ben DC's frontend guidelines:

- **Pick one time unit and stick to it.** This course uses milliseconds (`200ms`) everywhere, because they match JavaScript timers and design tokens. Mixing `200ms` and `0.2s` in one file is the actual bug.
- **Rotate in turns.** `rotate(0.25turn)` is a quarter turn, `rotate(1turn)` a full spin. Keep degrees for arbitrary angles like `14deg`.
- **Unitless line-heights**, `rem` for things that should scale with the reader's font size and `px` for hairlines.
- **Avoid `!important`**; it usually means a specificity fight the cascade should settle.

When you join an existing codebase, its conventions win. These are for when you're starting fresh.

**Fix the easing (paste into your agent):**

```text
Audit the CSS transitions and animations in this project. Replace any ease-in on UI with ease-out. Use these tokens: --ease-out: cubic-bezier(0.23, 1, 0.32, 1) for things entering or leaving, --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1) for things moving across the screen, --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1) for sheets. Use linear only for progress. Name the properties in every transition instead of "all", and keep durations in milliseconds.
```

**Check yourself:** A dropdown uses transition: opacity 250ms ease-in. A user says it feels slow. What's the best first fix?

- [ ] Make it 400ms so it's smoother
- [x] Switch to ease-out (or a strong custom ease-out) at the same or shorter duration
- [ ] Add a spring with bounce
- [ ] Use linear so the speed is even

*Why:* ease-in starts slowly exactly when the eye is watching, so the same 250ms feels slower. A strong ease-out moves at once and feels faster without changing the duration.

## In the skill

- https://school.agents.org.in/skill/motion/easing-curves.md
- https://school.agents.org.in/skill/motion/css-conventions.md
