Introduction
Physics-based animations create natural and satisfying movements that make your interfaces more intuitive and engaging. Unlike linear CSS transitions, physics simulations produce organic and predictable behaviors that users recognize instinctively.
In this tutorial, we will explore 5 essential physics animation techniques: bounce, springs, gravity, pendulum and elastic easing. Each technique is accompanied by an interactive demo and the complete code.
Physics animations rely mainly on requestAnimationFrame and custom cubic-bezier curves. These APIs are supported by all modern browsers.
1. Bounce Effect
The bounce effect is the most recognizable physics animation. It uses a specific Bezier curve to simulate a bouncing object, with natural deceleration at each contact with the ground.
.bounce-ball {
width: 50px;
height: 50px;
background: linear-gradient(135deg, #6366f1, #d946ef);
border-radius: 50%;
/* Custom bounce curve */
animation: bounce 1s
cubic-bezier(0.36, 0, 0.66, -0.56)
infinite alternate;
}
@keyframes bounce {
to {
transform: translateY(-150px);
}
}
How it works
The key to the bounce effect lies in the cubic-bezier curve:
- cubic-bezier(0.36, 0, 0.66, -0.56): the negative value of the 4th parameter creates an overshoot that simulates the bounce
- infinite alternate: the animation loops by alternating direction, creating a natural back-and-forth movement
- translateY: the vertical displacement simulates the effect of gravity
2. Spring Animation
The spring animation combines displacement and deformation for an organic effect. The scale applies a squish that mimics a soft object attached to a spring.
/* Elastic cubic-bezier for spring effect */
.spring-ball {
width: 50px;
height: 50px;
background: linear-gradient(135deg, #6366f1, #d946ef);
border-radius: 50%;
animation: spring 0.6s
cubic-bezier(0.68, -0.55, 0.265, 1.55)
infinite alternate;
}
@keyframes spring {
to {
/* Deplacement + deformation */
transform:
translateY(-100px)
scale(1.1, 0.9);
}
}
The value cubic-bezier(0.68, -0.55, 0.265, 1.55) is often called "easeInOutBack". Negative values and values greater than 1 create the elastic overshoot characteristic of springs.
3. Gravity Simulation
For a truly realistic gravity simulation, JavaScript must be used. Velocity and position are calculated at each frame by applying a gravity constant, with a bounce coefficient for damping.
const ball = document.querySelector('.gravity-ball');
let y = 0;
let velocity = 0;
const gravity = 0.5; // Gravity force
const bounceCoef = 0.7; // Bounce coefficient
const floor = 150; // Floor position
function animate() {
// Apply gravity to velocity
velocity += gravity;
y += velocity;
// Collision with floor
if (y >= floor) {
y = floor;
velocity *= -bounceCoef; // Inverser + amortir
}
// Stop when energy is depleted
if (Math.abs(velocity) < 0.5 && y >= floor - 1) {
y = floor;
return;
}
ball.style.top = y + 'px';
requestAnimationFrame(animate);
}
animate();
Key parameters
- gravity (0.5): the downward acceleration at each frame. The higher the value, the faster the fall
- bounceCoef (0.7): determines how much energy is retained after each bounce. 1.0 = perfect bounce, 0.0 = no bounce
- floor (150): the Y position of the floor in pixels. The ball bounces when it reaches this limit
Without a stop condition, the requestAnimationFrame loop runs indefinitely. Always add a minimum velocity threshold to stop the animation when the object is "at rest".
4. Pendulum Effect
The pendulum is a classic of physics simulation. It can be achieved in pure CSS by combining transform-origin and an animated rotation with sinusoidal easing.
.pendulum-container {
position: relative;
width: 100px;
height: 200px;
}
.pendulum-string {
position: absolute;
top: 0;
left: 50%;
width: 2px;
height: 150px;
background: #a1a1aa;
/* Pivot at top */
transform-origin: top center;
animation: swing 2s ease-in-out infinite;
}
.pendulum-ball {
position: absolute;
bottom: -25px;
left: 50%;
transform: translateX(-50%);
width: 50px;
height: 50px;
border-radius: 50%;
}
@keyframes swing {
0%, 100% {
transform: rotate(30deg);
}
50% {
transform: rotate(-30deg);
}
}
The ease-in-out easing is essential for simulating the natural slowing of the pendulum at the extremes of its motion, and acceleration at the center.
5. Elastic Easing
Elastic easing is perfect for user interactions: buttons, menus, modals. The elastic overshoot gives a satisfying visual feedback that makes the interface more lively and responsive.
.elastic-btn {
padding: 16px 32px;
background: #6366f1;
color: white;
border: none;
border-radius: 12px;
cursor: pointer;
font-weight: 600;
/* Elastic easing */
transition: transform 0.3s
cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.elastic-btn:hover {
transform: scale(1.1);
}
.elastic-btn:active {
transform: scale(0.95);
}
You can also create a more advanced elastic easing in JavaScript for custom animations:
// Custom elastic easing function
function elasticOut(t) {
const p = 0.3;
return Math.pow(2, -10 * t)
* Math.sin((t - p / 4)
* (2 * Math.PI) / p) + 1;
}
// Usage with a manual animation
function animateElastic(element, from, to, duration) {
const start = performance.now();
function tick(now) {
const t = Math.min((now - start) / duration, 1);
const progress = elasticOut(t);
const value = from + (to - from) * progress;
element.style.transform =
`scale(${value})`;
if (t < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
Best practices
Before concluding, here are some recommendations for using physics animations effectively:
Performance
- Use
transformandopacityonly for animations. These properties are composited by the GPU and do not trigger reflow - Limit simultaneous active JavaScript simulations. Each
requestAnimationFrameconsumes resources - Add
will-change: transformon animated elements to warn the browser - Prefer CSS when possible: CSS animations are often more performant than their JavaScript equivalent
Design and UX
- Keep durations short: 200-500ms for micro-interactions, 500ms-1s for decorative animations
- Stay consistent: use the same type of easing throughout your interface
- Don't overload: one or two physics animations per page is enough
Accessibility
/* Disable animations for sensitive users */
@media (prefers-reduced-motion: reduce) {
.bounce-ball,
.spring-ball,
.pendulum-string {
animation: none;
}
.elastic-btn {
transition: none;
}
}
Always verify that prefers-reduced-motion is respected. For JavaScript simulations, test this media query with window.matchMedia and disable animations accordingly.
Conclusion
Physics animations transform a static interface into a lively and intuitive experience. By mastering custom cubic-bezier curves and JavaScript simulations with requestAnimationFrame, you can create interactions that feel natural and satisfying.
The five techniques presented here cover the most common use cases: bounce for notifications, spring for element transitions, gravity for realistic simulations, pendulum for decorative animations, and elastic easing for micro-interactions.
Don't hesitate to experiment with values and parameters to find the perfect balance between realism and performance for your project.
Find dozens of ready-to-use animation effects in our effects library, with one-click copyable code.