# When to Use Spring Animations vs CSS Transitions: A Complete Decision Guide

> Decide between spring animations vs CSS transitions. Use CSS for static fades and hovers, springs for dynamic drag interactions that retain velocity. Optimize your UI.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: best-practices
- Published: 2026-07-31

---

**Use CSS transitions for predetermined, static motions like hovers and fades, and choose spring animations for gesture‑driven, interruptible interactions that must preserve velocity like drag‑to‑dismiss sheets.**

The `emilkowalski/skills` repository defines clear animation standards that govern when to choose spring animations versus CSS transitions in modern UI development. According to [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md), the decision hinges on whether your motion requires physics‑based interruptibility or deterministic time‑based control.

## Predetermined Motion: Choose CSS Transitions

CSS transitions excel when start and end states are known ahead of time. The standards specify that **CSS transitions can be interrupted and retargeted mid‑animation**, making them ideal for static interactions that do not react to ongoing user input.

Apply CSS transitions for:

- **Button hovers and focus states** – Simple `translateY` or `background` shifts that complete within 150–300 ms.
- **Opacity and color fades** – The standards recommend a 125–200 ms duration for tooltips and a strong custom easing curve defined in the document [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) (lines 31‑34 and 41‑45).
- **Performance‑critical paths** – CSS transitions run on the compositor thread, avoiding the main thread. As noted in lines 123‑124 of the standards file, “CSS animations beat JS under load.”

```css
/* Defined in skills/review-animations/STANDARDS.md L31-L34 */
:root {
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
}

.button {
  background: #0066ff;
  transition: background-color 150ms var(--ease-out),
              transform 150ms var(--ease-out);
}

.button:hover {
  background: #0055dd;
  transform: translateY(-2px);
}

```

## Dynamic, Gesture‑Driven Motion: Choose Spring Animations

Spring animations (typically driven by libraries like Motion or Framer Motion) carry **velocity when interrupted**, creating natural physics that respond to user gestures. According to [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) (lines 61‑73), springs are recommended for “drag with momentum, ‘alive’ elements, [and] interruptible gestures.”

Use springs when:

- **Implementing drag‑to‑dismiss sheets** – The animation must inherit release velocity rather than restarting from zero.
- **Creating elastic or bouncy layout changes** – Springs expose parameters such as `mass`, `stiffness`, `damping`, and `bounce` for fine‑grained control (lines 65‑70).
- **Animating unsupported CSS properties** – JavaScript springs can drive scroll positions or canvas coordinates that CSS cannot touch.

The repository provides an Apple‑style spring configuration (lines 65‑68) optimized for natural motion:

```tsx
import { motion, useSpring } from "motion";

export function BottomSheet() {
  // Apple-style spring: duration 0.5s, bounce 0.2
  const y = useSpring(0, { type: "spring", bounce: 0.2, duration: 0.5 });

  const handleDrag = (event: PointerEvent, info: { delta: { y: number } }) => {
    y.set(y.get() + info.delta.y);
  };

  const handleRelease = (event: PointerEvent, info: { velocity: { y: number } }) => {
    // Preserve release velocity for natural feel
    if (Math.abs(y.get()) < 150) {
      y.set(0, { velocity: info.velocity.y });
    } else {
      y.set(400); // dismiss
    }
  };

  return (
    <motion.div
      style={{ y }}
      drag="y"
      dragConstraints={{ top: 0, bottom: 0 }}
      onDrag={handleDrag}
      onDragEnd={handleRelease}
      className="sheet"
    />
  );
}

```

## Interruptibility: The Critical Differentiator

The `emilkowalski/skills` standards emphasize **interruptibility** as the primary architectural difference. CSS transitions can be retargeted mid‑flight without jarring resets, whereas traditional keyframe animations restart from zero (lines 77‑84). Spring animations inherit this advantage because they re‑evaluate continuously based on current state and velocity.

- **CSS transitions** – Retargetable mid‑animation; deterministic timing.
- **Spring animations** – Maintain momentum when interrupted; physics‑based settling time.
- **CSS keyframes** – Cannot be retargeted; restart from initial values.

## Hybrid Approaches: Mixing Both Techniques

Complex components often combine both techniques. Animate inexpensive properties like `opacity` with CSS‑style transitions (100–160 ms as per lines 43‑44) while driving positional changes with springs.

```tsx
import { motion } from "motion";

export function Toast({ message }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0, scale: 1 }}
      exit={{ opacity: 0, y: 20 }}
      transition={{
        opacity: { duration: 0.12, ease: "ease-out" },   // CSS-like
        y: { type: "spring", duration: 0.4, bounce: 0.1 }, // Spring-driven
        scale: { type: "spring", bounce: 0, duration: 0.3 }
      }}
      className="toast"
    >
      {message}
    </motion.div>
  );
}

```

## Performance Under Load

When the main thread is busy, CSS transitions remain smooth because they are hardware‑accelerated and run off the main thread. The standards file explicitly warns that JavaScript‑driven springs may jank under heavy load, whereas CSS transitions (or Web Animations API) remain the safer choice for performance‑critical UI (lines 123‑124).

## Summary

- **Use CSS transitions** for predetermined motion, simple color/opacity changes, and when main‑thread performance is critical.
- **Use spring animations** for drag gestures, momentum‑based interactions, and any UI that must feel “alive” and interruptible.
- **Reference [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md)** for exact duration guidelines (125–200 ms for tooltips, under 300 ms for UI feedback) and spring configurations.
- **Leverage interruptibility**—springs preserve velocity when retargeted, while CSS transitions provide deterministic mid‑flight retargeting that keyframes cannot match.

## Frequently Asked Questions

### Can CSS transitions be interrupted mid‑animation?

Yes. According to [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) (lines 77‑84), CSS transitions can be retargeted mid‑animation, allowing smooth direction changes when a user hovers off an element or toggles a state before the previous transition completes.

### What spring configuration should I use for mobile gestures?

The repository recommends an Apple‑style spring with `bounce: 0.2` and `duration: 0.5` for natural drag interactions (lines 65‑68). For tighter controls, adjust `stiffness` and `damping` instead of using duration-based springs.

### Are CSS transitions always more performant than spring animations?

Generally yes. CSS transitions run on the compositor thread and are hardware‑accelerated. The standards note that “CSS animations beat JS under load” (lines 123‑124), making them preferable when the main thread is occupied or on low‑end devices.

### How do I decide when to mix CSS transitions and springs in the same component?

Use CSS transitions for properties that are cheap to animate and require deterministic timing (like `opacity` fades under 160 ms), and springs for positional changes that require physics (like `y` or `x` transforms). The `emilkowalski/skills` codebase demonstrates this hybrid approach in [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md), showing that separating concerns optimizes both performance and perceived quality.