CSS Animation Keyframes Tutorial: Create Smooth Animations from Scratch

1 Mar 2026 · 8 min read

CSS keyframes are the foundation of creating sophisticated animations on the web. Whether you want to build subtle hover effects or complex interactive animations, mastering CSS animation keyframes is essential for modern web development. This comprehensive guide will teach you everything from basic syntax to advanced techniques for creating smooth, performant animations.

Unlike simple transitions that animate between two states, keyframes allow you to define multiple steps in an animation sequence, giving you precise control over timing, easing, and visual effects.

Understanding CSS Keyframes Syntax and Structure

CSS keyframes are defined using the @keyframes rule, which establishes a timeline for your animation. Each keyframe represents a specific point in time during the animation sequence.

@keyframes animationName { 0% { /* Starting state */ transform: translateX(0); opacity: 1; } 50% { /* Midpoint state */ transform: translateX(50px); opacity: 0.5; } 100% { /* End state */ transform: translateX(100px); opacity: 0; } }

You can use percentages (0% to 100%) or the keywords from (equivalent to 0%) and to (equivalent to 100%). Percentages offer more flexibility when you need intermediate steps in your animation.

To apply a keyframe animation to an element, use the animation property:

.animated-element { animation: animationName 2s ease-in-out infinite; }

Creating Your First Keyframe Animation

Let's create a simple but effective animation that demonstrates the power of css keyframes animation. We'll build a pulsing effect that's perfect for drawing attention to important elements.

@keyframes pulse { 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(124, 106, 255, 0.7); } 70% { transform: scale(1.05); box-shadow: 0 0 0 20px rgba(124, 106, 255, 0); } 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(124, 106, 255, 0); } } .pulse-button { background: #7c6aff; border: none; border-radius: 8px; padding: 12px 24px; color: white; animation: pulse 2s infinite; }
Pulse Button

This animation combines scaling and shadow effects to create a compelling pulse effect. The key is using an intermediate keyframe at 70% to control the timing of the shadow expansion.

Try it yourself → Experiment with gradient animations using our CSS Gradient Generator to create stunning visual effects.

Open CSS Gradient Generator

Animation Properties Breakdown

The animation shorthand property accepts multiple values:

animation: name duration timing-function delay iteration-count direction fill-mode;

Duration controls how long one cycle takes, timing-function defines the easing curve, and iteration-count determines how many times the animation repeats. Use infinite for continuous loops.

Advanced Keyframes: Multiple Properties and Complex Timing

Creating css smooth animations requires understanding how to coordinate multiple properties and use advanced timing techniques. Let's build a sophisticated loading animation that combines rotation, scaling, and opacity changes.

@keyframes complexLoader { 0% { transform: rotate(0deg) scale(1); opacity: 1; border-radius: 50%; } 25% { transform: rotate(90deg) scale(0.8); opacity: 0.8; border-radius: 25%; } 50% { transform: rotate(180deg) scale(1.2); opacity: 0.6; border-radius: 10%; } 75% { transform: rotate(270deg) scale(0.9); opacity: 0.8; border-radius: 25%; } 100% { transform: rotate(360deg) scale(1); opacity: 1; border-radius: 50%; } } .complex-loader { width: 40px; height: 40px; background: linear-gradient(45deg, #7c6aff, #4ade80); animation: complexLoader 3s cubic-bezier(0.4, 0, 0.2, 1) infinite; }

Timing Functions for Natural Movement

The secret to smooth animations lies in choosing the right easing functions. CSS offers several built-in options:

/* Built-in timing functions */ ease: cubic-bezier(0.25, 0.1, 0.25, 1) ease-in: cubic-bezier(0.42, 0, 1, 1) ease-out: cubic-bezier(0, 0, 0.58, 1) ease-in-out: cubic-bezier(0.42, 0, 0.58, 1) /* Custom easing for natural motion */ animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);

Custom cubic-bezier curves allow you to create unique motion characteristics. The values (0.4, 0, 0.2, 1) create a Material Design-inspired "ease" that feels natural and responsive.

Combining Animations with Gradients and Visual Effects

One of the most powerful techniques in modern web design is combining keyframe animations with CSS gradients and visual effects. This creates dynamic, engaging interfaces that capture user attention.

@keyframes gradientShift { 0% { background-position: 0% 50%; transform: translateY(0) scale(1); } 50% { background-position: 100% 50%; transform: translateY(-5px) scale(1.02); } 100% { background-position: 0% 50%; transform: translateY(0) scale(1); } } .gradient-card { background: linear-gradient(270deg, #7c6aff, #4ade80, #f59e0b); background-size: 300% 300%; padding: 20px; border-radius: 12px; color: white; animation: gradientShift 4s ease-in-out infinite; }
Animated Gradient Card

This technique animates the background-position property of a gradient that's larger than its container, creating a smooth color transition effect. Combined with subtle transform changes, it creates a lively, modern aesthetic.

Staggered Animations for Complex Sequences

When animating multiple elements, staggering the animation delays creates sophisticated choreographed effects:

.stagger-item:nth-child(1) { animation-delay: 0s; } .stagger-item:nth-child(2) { animation-delay: 0.1s; } .stagger-item:nth-child(3) { animation-delay: 0.2s; } .stagger-item:nth-child(4) { animation-delay: 0.3s; }

Design beautiful gradients → Create stunning animated gradients with perfect color combinations for your keyframe animations.

Try CSS Gradient Generator

Performance Optimization and Best Practices

Creating performant animations is crucial for maintaining smooth user experiences across all devices. Following these optimization techniques ensures your css animation tutorial knowledge translates to real-world success.

Animate Only Transform and Opacity

For the smoothest animations, stick to properties that don't trigger layout recalculations:

/* ✅ Performant properties */ transform: translateX() translateY() scale() rotate(); opacity: 0-1; /* ❌ Avoid animating these */ width, height, top, left, margin, padding

Transform and opacity changes are handled by the GPU, resulting in 60fps animations even on lower-end devices.