# How to Implement Proper Easing Curves for UI Animations: A Complete Guide

> Master UI animations with custom cubic-bezier curves. Discover how to implement proper easing for engaging and performant user interfaces. Learn best practices for durations and interactive elements.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: how-to-guide
- Published: 2026-08-03

---

**Use strong custom cubic-bezier curves stored as design tokens instead of built-in CSS easings, keeping durations under 300ms and avoiding ease-in for interactive elements.**

The `emilkowalski/skills` repository—developed for the Instagit codebase—codifies a rigorous approach to implementing proper easing curves for UI animations through comprehensive skill documents. These standards establish that motion should feel deliberate and responsive, moving beyond default browser easing to create interfaces that communicate intent clearly.

## Why Built-In CSS Easings Are Too Weak

Default browser easings such as `ease`, `ease-in`, `ease-out`, and `linear` are intentionally gentle and often feel sluggish for deliberate UI actions. According to [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md), the team explicitly warns that "Built-in CSS easings are too weak. Use strong custom curves" to ensure animations feel snappy and purposeful rather than floating or delayed.

## Selecting Strong Cubic-Bezier Curves

When implementing proper easing curves for UI animations, select "strong" cubic-bezier functions that provide a quick start and a smooth finish. The standards recommend sourcing curves from **easing.dev** and **easings.co** as curated resources for proven timing functions.

For entrance animations, [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md) recommends a default curve of `cubic-bezier(0.77, 0, 0.175, 1)`—a fast-out, slow-in curve that brings elements into view with immediate responsiveness. Pair this with durations under **300ms** to maintain a sense of instantaneous feedback.

## Token-Driven Easing Architecture

Centralizing easing definitions as design tokens ensures consistency across components and simplifies auditing. As documented in [`skills/prototype/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/prototype/SKILL.md), all easing values should be stored as tokens (e.g., `--easing-enter`, `--easing-leave`) rather than hard-coded values.

### Defining Easing Design Tokens

Define your curves once in a global stylesheet to create a single source of truth:

```css
:root {
  --easing-enter: cubic-bezier(0.77, 0, 0.175, 1);
  --easing-leave: cubic-bezier(0.4, 0, 1, 1);
  --duration-enter: 250ms;
  --duration-leave: 200ms;
}

```

### Consuming Tokens in CSS and JavaScript

Reference these tokens in component styles to maintain the established motion language:

```css
.my-modal {
  opacity: 0;
  transform: translateY(10px);
  animation: fadeIn var(--duration-enter) var(--easing-enter) forwards;
}

@keyframes fadeIn {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

```

For JavaScript-driven animations using the Web Animations API, reference the same cubic-bezier values:

```javascript
const elem = document.querySelector('.my-modal');
elem.animate(
  [
    { opacity: 0, transform: 'translateY(10px)' },
    { opacity: 1, transform: 'translateY(0)' }
  ],
  {
    duration: 250,
    easing: 'cubic-bezier(0.77, 0, 0.175, 1)',
    fill: 'forwards'
  }
);

```

In React with styled-components, import and apply these tokens through shared constants:

```tsx
import styled, { css } from 'styled-components';

const fadeIn = css`
  opacity: 0;
  transform: translateY(10px);
  animation: 250ms cubic-bezier(0.77,0,0.175,1) forwards fadeIn;
`;

const Modal = styled.div`
  ${fadeIn}
`;

```

## Entrance and Exit Animation Strategies

The audit criteria in [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md) establish strict rules for applying easing curves. Use `ease-out` (or your custom `--easing-enter` token) for entrance animations to create a sense of immediate response. Critically, avoid `ease-in` on interactive UI elements, as the document states: "`ease-in` on UI is always a finding."

When elements exit the viewport, use quicker durations (around 200ms) with curves that accelerate out rather than decelerate, preventing the interface from feeling sticky.

## Accessibility and Performance Considerations

Proper easing must respect user preferences and hardware constraints. Always check for `prefers-reduced-motion` before executing animations:

```javascript
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

if (!prefersReduced) {
  elem.animate(keyframes, { duration: 250, easing: 'cubic-bezier(0.77,0,0.175,1)' });
}

```

For cross-fade transitions that feel harsh even with proper easing, [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) suggests adding a subtle blur filter: `filter: blur(2px)`. Never exceed **20px** of blur, as larger values create performance bottlenecks during the compositing phase.

## Summary

- **Avoid built-in easings**: Default CSS values like `ease` and `ease-in` are too weak for deliberate UI motion.
- **Use strong cubic-bezier curves**: Source curves from easing.dev or easings.co, such as `cubic-bezier(0.77, 0, 0.175, 1)` for entrances.
- **Tokenize everything**: Store curves in CSS variables (e.g., `--easing-enter`) to centralize definitions and simplify audits.
- **Mind the duration**: Keep entrance animations under 300ms and exit animations faster (around 200ms).
- **Respect accessibility**: Check `prefers-reduced-motion` and limit blur effects to under 20px.

## Frequently Asked Questions

### Why are built-in CSS easings considered too weak for UI animations?

Built-in easings like `ease`, `ease-in`, and `linear` are designed to be gentle and unobtrusive, which makes them feel sluggish when users expect immediate feedback from interactive elements. According to [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md), strong custom cubic-bezier curves provide the snappy, purposeful feel that modern interfaces require.

### What duration should I use for entrance animations?

Keep entrance animations under **300ms** to maintain the perception of instantaneous response. The [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md) document recommends 250ms as a standard duration for most UI motions, paired with a fast-out curve like `cubic-bezier(0.77, 0, 0.175, 1)`.

### How should I handle users who prefer reduced motion?

Always check `window.matchMedia('(prefers-reduced-motion: reduce)')` before executing animations. If the user prefers reduced motion, skip the animation or provide an instant state change instead, ensuring your interface remains accessible without causing vestibular discomfort.

### Why should I avoid ease-in for interactive UI elements?

`ease-in` starts slowly and accelerates, which creates a perception of lag or unresponsiveness when applied to buttons, menus, or modal entrances. The [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md) explicitly flags "`ease-in` on UI is always a finding" because it contradicts the expectation of immediate feedback in interactive systems.