# CSS Hover State with Custom Easing: Implementation Guide and Code Examples

> Learn to create smooth CSS hover states with custom cubic bezier easing. This guide provides implementation details and code examples for intuitive animations.

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

---

**Apply a `transition` with a `cubic-bezier()` timing function to the base element selector to create bidirectional hover animations that feel smooth and intentional.**

The emilkowalski/skills repository structures frontend knowledge as discrete, reusable "skills" documented in Markdown. According to the patterns established in [`skills/animate/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md) and [`skills/animate/RECIPES.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md), implementing a CSS hover state with custom easing requires declaring your `transition` properties on the base selector—not the `:hover` state—so the browser can animate both the entrance and exit phases using your specified easing curve.

## How CSS Hover Transitions Work

### The Four-Step Foundation

1. **Define the default style** – Establish the element’s baseline appearance (size, color, position).
2. **Add a `:hover` rule** – Specify the visual change you want, such as `transform: scale(1.08)` or `background-color: #fff`.
3. **Apply a `transition`** – Instruct the browser to animate property changes over a specific duration.
4. **Choose a custom easing function** – Use `cubic-bezier(x1, y1, x2, y2)` to craft motion curves that match your design language.

Because the transition is declared on the base selector, the browser interpolates values in both directions—entering and leaving hover—ensuring no flicker or abrupt jumps.

### Why Custom Easing Matters

- **Brand consistency** – A unique cubic-bezier curve defines motion as distinctly as a color palette or typeface.
- **Perceived performance** – An "ease-out-back" curve can make a 250ms animation feel snappier than a linear 400ms transition.
- **Fine-grained control** – Create anticipation, overshoot, or elastic effects without JavaScript libraries.

## Practical Code Examples

### Simple Hover Scale with Overshoot

This example from the repository's animation patterns creates a button that scales up with a bouncy overshoot effect:

```css
.button {
  display: inline-block;
  padding: .6rem 1.2rem;
  background: #0066ff;
  color: #fff;
  border-radius: .4rem;
  text-align: center;
  /* Base transition – everything that changes on hover */
  transition: transform 250ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

.button:hover {
  transform: scale(1.08);
}

```

**Result:** When the cursor enters, the button enlarges with a lively overshoot; when the cursor leaves, it returns smoothly along the same curve.

### Multi-Property Card Hover

For complex UI elements like cards, transition multiple properties simultaneously using consistent easing:

```css
.card {
  background: #fafafa;
  border: 1px solid #e0e0e0;
  border-radius: .5rem;
  box-shadow: 0 2px 4px rgba(0,0,0,.1);
  transition:
    background-color 200ms cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow      200ms cubic-bezier(0.4, 0, 0.2, 1),
    transform       200ms cubic-bezier(0.4, 0, 0.2, 1);
}

.card:hover {
  background-color: #fff;
  box-shadow: 0 8px 16px rgba(0,0,0,.12);
  transform: translateY(-4px);
}

```

**Result:** The card lifts, brightens, and deepens its shadow with Material Design-compatible easing defined by `cubic-bezier(0.4, 0, 0.2, 1)`.

### Reusable Easing with CSS Variables

To maintain consistency across large projects, define your easing curves as CSS variables. This pattern aligns with the standardization approach found in [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md):

```css
:root {
  --easing-soft: cubic-bezier(0.25, 0.1, 0.25, 1);
}

/* Apply the variable wherever a transition is needed */
.nav-link {
  color: #333;
  transition: color 180ms var(--easing-soft);
}

.nav-link:hover {
  color: #0066ff;
}

```

**Result:** Centralizing the curve in `:root` allows you to adjust the motion feel site-wide by changing a single value.

## Repository Integration

To contribute a dedicated "Hover-Easing" skill to the emilkowalski/skills collection, follow the established folder structure demonstrated in [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md):

```

skills/
└─ hover-easing/
   ├─ SKILL.md          ← High-level description: "Create smooth hover states with custom cubic-bezier curves"
   ├─ RECIPES.md        ← Ready-to-copy CSS examples (like those above)
   └─ REFERENCES.md     ← Links to cubic-bezier visualization tools and design system docs

```

Reference the core principles in [`skills/animate/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md) when documenting your implementation, and audit your motion against the checklist in [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md) to ensure accessibility and performance standards.

## Summary

- **Declare transitions on the base selector**, not the `:hover` pseudo-class, to ensure smooth bidirectional animation.
- **Use `cubic-bezier(x1, y1, x2, y2)`** instead of keywords like `ease` or `linear` for brand-specific motion curves.
- **Apply CSS variables** for easing values to maintain consistency across components and simplify global updates.
- **Reference [`skills/animate/RECIPES.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md)** in the emilkowalski/skills repository for battle-tested animation patterns and integration guidelines.

## Frequently Asked Questions

### How does `cubic-bezier` work in CSS transitions?

The `cubic-bezier(x1, y1, x2, y2)` function defines a Bézier curve where the x-axis represents time progression (0 to 1) and the y-axis represents the animation's progress (0 to 1). The four values control the curve's control points, allowing you to create custom acceleration and deceleration patterns that standard keywords cannot achieve.

### Should I declare the `transition` property on the base element or the `:hover` state?

Always declare `transition` on the base element selector. When placed on `:hover`, the transition only applies when entering the hover state, causing an abrupt jump when the mouse leaves. Declaring it on the base ensures the browser animates both entering and exiting phases using your specified duration and easing.

### What are common cubic-bezier values for UI animations?

**Standard smooth:** `cubic-bezier(0.4, 0, 0.2, 1)` (Material Design standard), **Soft ease:** `cubic-bezier(0.25, 0.1, 0.25, 1)`, and **Overshoot/bounce:** `cubic-bezier(0.68, -0.55, 0.265, 1.55)`. Values outside the 0-1 range for the y-axis create anticipation or overshoot effects.

### How do I maintain consistent easing across a large project?

Define your easing curves as CSS custom properties (variables) in `:root`, as shown in [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md). Reference these variables in your transition declarations rather than hardcoding values, allowing you to update the motion system globally by editing a single line.