# CSS Example: Button Press with Custom Easing in emilkowalski/skills

> Learn how to create a custom button press animation in CSS using transform scale and cubic bezier easing for a tactile and responsive user experience.

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

---

**Use `transform: scale(0.97)` combined with a custom `cubic-bezier(0.77, 0, 0.175, 1)` easing curve to create tactile, responsive button press animations.**

The **skills** repository by Emil Kowalski treats UI motion as a first-class design concern. This CSS example demonstrates how to implement a polished button press using the repository's layered architecture of design tokens, recipes, and standards—replacing weak built-in easings with deliberate, custom curves.

## Architecture of Button Press Handling

The repository organizes animation guidance across focused modules that work together:

- **review-animations/STANDARDS.md** – Defines baseline CSS patterns for interactive states, including a deliberately slow 2-second linear overlay transition for a "thoughtful" press feel. [[Line 107]](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md#L107)

- **animate/RECIPES.md** – Provides ready-to-copy implementation recipes, including the minimal `.button:active` rule and overlay clip-path approach. [[Lines 18, 207, 212]](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md#L18)

- **emil-design-eng/SKILL.md** – Enforces easing and duration tokens with custom cubic-bezier curves that replace standard `ease-in`/`ease-out`. [[Lines 208, 303, 417, 598]](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md#L208)

- **apple-design/SKILL.md** – Recommends reacting on `:active` (pointer-down) rather than waiting for click release. [[Line 30]](https://github.com/emilkowalski/skills/blob/main/skills/apple-design/SKILL.md#L30)

### Three-Layer System

1. **Token layer** – Centralized design tokens for easing curves and durations
2. **Recipe layer** – Reusable, implementation-ready snippets
3. **Standard layer** – Opinionated defaults and quality guidelines

## Why Custom Easing Matters

Built-in CSS easings are explicitly deemed "too weak" for deliberate UI motion in **STANDARDS.md**. The repository advocates for **strong cubic-bezier curves** that provide quick acceleration followed by smooth settlement.

Recommended curve from **emil‑design‑eng/SKILL.md**: `cubic-bezier(0.77, 0, 0.175, 1)`

These curves live as design tokens, ensuring every component shares consistent motion language.

## Complete CSS Example

This self-contained snippet follows the repository's guidance with three essential ingredients: scale-on-press feedback, overlay clip-path animation, and sub-300ms durations.

```css
/* -------------------------------------------------------------
   Core button – uses the repo's "scale on press" token
   ------------------------------------------------------------- */
.button {
  position: relative;               /* required for overlay positioning */
  display: inline-block;
  padding: 0.5rem 1rem;
  background: #0069ed;
  color: #fff;
  border-radius: 0.25rem;
  cursor: pointer;
  /* Repository-wide default easing token */
  transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* -------------------------------------------------------------
   Press state – immediate tactile feedback on pointer-down
   ------------------------------------------------------------- */
.button:active {
  transform: scale(0.97);          /* tokenized "press-scale" value */
}

/* -------------------------------------------------------------
   Optional overlay – visual "fill" with custom easing
   ------------------------------------------------------------- */
.button .overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.1);
  /* Start fully clipped on right side */
  clip-path: inset(0 100% 0 0);
  /* Custom strong easing from token list */
  transition: clip-path 0.25s cubic-bezier(0.77, 0, 0.175, 1);
}

/* Reveal overlay when button is pressed */
.button:active .overlay {
  clip-path: inset(0 0 0 0);
}

```

### Mapping to Repository Sources

| Implementation Detail | Source File |
|---|---|
| `transform` transition with cubic-bezier | **animate/RECIPES.md** – custom easing for UI actions |
| Baseline slow overlay (`2s linear`) | **review-animations/STANDARDS.md** [[L107]](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md#L107) |
| Custom curve `cubic-bezier(0.77,0,0.175,1)` | **emil-design-eng/SKILL.md** – "critical: use custom easing curves" [[L108-123]](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md#L208) |
| `:active` for pointer-down response | **apple-design/SKILL.md** [[L30]](https://github.com/emilkowalski/skills/blob/main/skills/apple-design/SKILL.md#L30) |

Replace token values with your project's CSS variables (e.g., `var(--duration-quick)`, `var(--easing-strong)`) for production use.

## Key Source Files

| File | Contents | Link |
|---|---|---|
| [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) | Canonical CSS patterns for interaction states | [View](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) |
| [`skills/animate/RECIPES.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md) | Ready-to-copy component recipes | [View](https://github.com/emilkowalski/skills/blob/main/skills/animate/RECIPES.md) |
| [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) | Design token definitions and rationale | [View](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) |
| [`skills/apple-design/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/apple-design/SKILL.md) | Platform UX notes including `:active` behavior | [View](https://github.com/emilkowalski/skills/blob/main/skills/apple-design/SKILL.md) |
| [`skills/animate/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md) | Animation system overview | [View](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md) |

## Summary

- **Scale transform** (`0.97`) provides immediate tactile confirmation on `:active`
- **Custom cubic-bezier** curves replace weak built-in easings for deliberate, quality motion
- **Clip-path overlay** adds visual depth when extended with the repository's 2s baseline pattern
- **Pointer-down response** on `:active` beats click-delayed feedback for perceived responsiveness

## Frequently Asked Questions

### What makes a cubic-bezier curve "strong" for button animations?

A strong curve has pronounced acceleration and deceleration phases. The repository's recommended `cubic-bezier(0.77, 0, 0.175, 1)` starts fast (0.77 x-velocity) and settles smoothly, creating responsive yet polished motion. Weak curves like `ease-in-out` distribute acceleration too evenly, feeling sluggish or unremarkable.

### Why react on `:active` instead of JavaScript click handlers?

[`apple-design/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/apple-design/SKILL.md) emphasizes that `:active` triggers on pointer-down, providing **immediate visual feedback**. Click handlers wait for pointer-up, introducing perceptible lag. The CSS-only approach also performs better and respects reduced-motion preferences through native media queries.

### How do I adjust timing without breaking the repository's standards?

Maintain the **sub-300ms budget** for primary motion (scale, color shifts). The optional overlay effect in **STANDARDS.md** intentionally uses 2 seconds as a "slow, deliberate" exception—keep this separate from interactive feedback to avoid perceived unresponsiveness.

### Can I use this with CSS-in-JS or Tailwind?

Absolutely. Map the repository's tokens to your system's variables: the cubic-bezier values become theme constants, durations become spacing-scale tokens, and the clip-path overlay becomes a reusable component variant. The architectural principles remain identical across implementation methods.