When to Use Spring Animations vs CSS Transitions: A Complete Decision Guide
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, 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
translateYorbackgroundshifts 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(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.”
/* 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 (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, andbouncefor 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:
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.
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.mdfor 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 (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, showing that separating concerns optimizes both performance and perceived quality.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →