Home / Articles / Animation & Motion /

animationeasing

cubic-bezier(): custom easing curves

The named keywords cover common cases, but custom curves let you craft animations that feel uniquely alive — bouncy, snappy, or dramatically weighted.

How cubic-bezier() works

A cubic Bezier curve is defined by four numbers — two control points, each with an x and y coordinate. The x axis represents time (0 to 1) and the y axis represents progress (0 to 1).

/* cubic-bezier(x1, y1, x2, y2) */

/* The named keywords as cubic-bezier values */
ease:        cubic-bezier(0.25, 0.1, 0.25, 1.0)
ease-in:     cubic-bezier(0.42, 0.0, 1.0, 1.0)
ease-out:    cubic-bezier(0.0, 0.0, 0.58, 1.0)
ease-in-out: cubic-bezier(0.42, 0.0, 0.58, 1.0)
linear:      cubic-bezier(0.0, 0.0, 1.0, 1.0)

The x values must stay between 0 and 1 (they represent time, which can't go backwards). The y values can exceed that range — that's how you create overshoot and bounce effects.

Snappy deceleration

The most universally useful custom curve: a fast start with a long, gentle slowdown. It feels responsive because the element moves immediately.

.panel {
  transform: translateX(-100%);
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.panel.is-open {
  transform: translateX(0);
}

The y1 value of 1 means the element covers most of its distance early, then eases into its final position. This is the go-to curve for slide-in panels and modals.

Overshoot and spring

When y2 exceeds 1, the animation overshoots its target before settling back. This creates a spring-like bounce.

/* Subtle overshoot */
.badge {
  transform: scale(0);
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.badge.is-visible {
  transform: scale(1);
  /* Scales slightly past 1, then settles back */
}

/* Dramatic spring */
.notification {
  transform: translateY(-20px);
  opacity: 0;
  transition:
    transform 0.5s cubic-bezier(0.17, 1.67, 0.29, 0.97),
    opacity 0.3s ease;
}

.notification.show {
  transform: translateY(0);
  opacity: 1;
}
Overshoot values above 1.5 on y1 or y2 create increasingly exaggerated bounces. Keep them under 1.8 for UI — beyond that it looks glitchy.

Slow-in for dramatic reveals

A strong ease-in starts slow and accelerates. Use it for elements that should build anticipation — a hero image loading in, or a counter reaching its value.

.counter {
  /* Slow start, fast finish */
  transition: all 1.2s cubic-bezier(0.7, 0, 0.84, 0);
}

/* More dramatic: barely moves at first, then rushes */
.reveal {
  transition: transform 0.8s cubic-bezier(0.85, 0, 0.15, 1);
  /* This is actually ease-in-out on steroids */
}

Strong ease-in curves are rare in UI because they feel sluggish. The element doesn't respond immediately, so users may think nothing happened. Reserve them for decorative animations.

Building a curve library

Define your curves as custom properties for consistency across your project. Name them by character, not by math.

:root {
  --ease-snappy: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-smooth: cubic-bezier(0.45, 0, 0.55, 1);
  --ease-dramatic: cubic-bezier(0.85, 0, 0.15, 1);
  --ease-spring: cubic-bezier(0.17, 1.67, 0.29, 0.97);
}

.card {
  transition: transform 0.3s var(--ease-snappy);
}

.modal {
  transition: transform 0.4s var(--ease-bounce);
}

This keeps your motion design consistent. When you want to adjust the feel of all bouncy animations, you change one custom property.

The new linear() function

For curves that cubic-bezier can't express — multi-bounce, elastic, or stepped — modern CSS offers linear() with arbitrary control points.

/* A multi-bounce elastic effect */
.elastic {
  transition: transform 0.6s linear(
    0, 0.22, 0.78, 1.15, 1, 0.94, 1, 0.98, 1
  );
}

/* Each value is the progress at evenly-spaced time points.
   Values above 1 = overshoot, below previous = bounce back */

The linear() function interpolates linearly between the given points. With enough points, you can approximate any curve — including true spring physics that cubic-bezier cannot express.