CSS Tutorial

CSS Animations: @keyframes, Timing Functions And Animation Properties Explained (2026-27)

By Pramod Behera  ·  Updated: June 2026  ·  14 min read
✅ In this CSS Tutorial – CSS Animations: Complete Guide to @keyframes, Timing Functions & All Animation Properties

Today we are discuss topic CSS Animations. CSS transitions can smoothly change a property when it's triggered — but CSS Animations go much further, running multi-step sequences automatically, looping forever, reversing, delaying, and pausing, all without a single line of JavaScript. In this complete guide you will master the @keyframes at-rule, and every animation property: animation-name, animation-duration, animation-timing-function (ease, linear, ease-in, ease-out, ease-in-out, cubic-bezier), animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, animation-play-state, and the compact animation shorthand. You'll also see real-world animation patterns — fade-in, slide, bounce, pulse, spinner, typewriter, and shake — and learn when to use each timing function. Includes live running demos, an interactive animation builder, comparison tables, common mistakes, a quiz, and FAQ. This tutorial or document breaks down the process step by step, using simple language and real-world examples to help you master the skill.

📋 Table of Contents

  1. What Are CSS Animations?
  2. @keyframes – Defining Animation Steps
  3. animation-name & animation-duration
  4. animation-timing-function – Speed Curves
  5. animation-delay – When the Animation Starts
  6. animation-iteration-count – Loops & infinite
  7. animation-direction – normal, reverse, alternate
  8. animation-fill-mode – forwards, backwards, both
  9. animation-play-state – Running & Paused
  10. The animation Shorthand
  11. Real-World Animation Patterns
  12. Animation Properties – Reference Table
  13. Best Practices
  14. Common Mistakes to Avoid
  15. Live Code Example
  16. Try It Yourself – Interactive Editor
  17. 🎨 Interactive Animation Builder
  18. Practice Quiz
  19. Frequently Asked Questions (FAQ)

✅ What Are CSS Animations?

CSS Animations let you animate an element through multiple style states over time, using @keyframes rules, without requiring any JavaScript. They can run automatically on page load, loop infinitely, reverse direction, and pause — making them the right tool for loading spinners, entrance effects, attention pulses, and motion that needs more than a simple A-to-B transition.

🎬
@keyframes
Defines the animation steps by name.
⏱️
duration
How long one cycle takes.
📈
timing-function
The speed curve of the motion.
🔁
iteration-count
How many times to repeat.
💡 Animations vs Transitions: CSS transitions watch for a property change then smoothly blend between two states. CSS animations run their own defined sequence automatically — you can have multiple steps, a delay, a loop count, a reverse, and a play/pause toggle, all without any trigger or JavaScript.

✅ @keyframes – Defining Animation Steps

@keyframes is a CSS at-rule where you define each step of an animation by name. Use from and to for a simple two-step animation, or percentage values (0%, 25%, 50%, 100%) to build multi-step sequences.

@keyframes – Live Running Demo
@keyframes slidein {
  from { transform: translateX(-100%); }
  to   { transform: translateX(0); }
}

/* Multi-step with percentages */
@keyframes colorpop {
  0%   { background: #0EA5E9; }
  50%  { background: #a78bfa; }
  100% { background: #0EA5E9; }
}
👁 Live Output – Color-Cycling Box
@keyframes
ℹ️ Naming tip: Give @keyframes names that describe what the animation doesslidein, fadeup, pulse — not what properties it changes. This makes your CSS far easier to read at a glance.

✅ animation-name And animation-duration

These two properties are the minimum needed to run any animation. animation-name links the element to a @keyframes rule by its exact name; animation-duration sets how long one full cycle takes — in seconds (s) or milliseconds (ms).

animation-name & duration – Live Running Demo
.spinner {
  animation-name: spin;
  animation-duration: 1.2s;
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
👁 Live Output
⚙️
⚠️ Common mistake: If the animation name doesn't exactly match the @keyframes name (including case), the animation silently fails to play — always double-check the name is identical in both places.

✅ animation-timing-function – Speed Curves

animation-timing-function controls how the animation accelerates and decelerates across its duration. The five keyword values cover the most common motion feels; cubic-bezier() gives you precise, custom control over any speed curve.

Timing Functions – Live Comparison
.linear { animation-timing-function: linear; }
.ease { animation-timing-function: ease; }
.ease-in { animation-timing-function: ease-in; }
.ease-out { animation-timing-function: ease-out; }
.ease-io { animation-timing-function: ease-in-out; }
👁 Watch the balls move at different speeds
linear
ease
ease-in
ease-out
ease-i-o
💡 When to use each: ease-out is best for entrance animations (things sliding or fading in), because fast-then-slow feels natural and responsive. ease-in is best for exit animations (things leaving the screen). ease-in-out works well for looping animations like pulses and bounces that need to feel smooth at both ends.

✅ animation-delay – When the Animation Starts

animation-delay holds the element in its pre-animation (or first-keyframe, with fill-mode: backwards) state for a set time before the animation begins. Negative values start the animation as if it's already been running for that duration.

animation-delay – Staggered Demo
.dot-1 { animation-delay: 0s; }
.dot-2 { animation-delay: 0.2s; }
.dot-3 { animation-delay: 0.4s; }

/* staggered bounce for a loading indicator */
👁 Staggered Bounce Dots
ℹ️ Staggering trick: Applying increasing animation-delay values to a list of identical elements (0s, 0.1s, 0.2s…) creates a "cascade" or "wave" entrance effect — one of the most popular CSS animation patterns in modern UI.

✅ animation-iteration-count – Loops & infinite

animation-iteration-count sets how many times the animation plays. A number plays it that many times and stops; infinite loops it forever — the standard value for spinners, pulses, and breathing effects.

iteration-count – 3 Times vs infinite
.plays-three {
  animation-iteration-count: 3;
}

.loops-forever {
  animation-iteration-count: infinite;
}
👁 Infinite Pulse – Loading Spinner
pulse

✅ animation-direction – normal, reverse, alternate

animation-direction controls which way through the @keyframes the animation runs each cycle: normal (start → end), reverse (end → start), alternate (start → end then end → start), or alternate-reverse.

animation-direction – Live Comparison
.normal { animation-direction: normal; }
.reverse { animation-direction: reverse; }
.alternate { animation-direction: alternate; }
👁 Watch direction differences
normal
reverse
alternate
💡 Tip: alternate is the cleanest way to create a smooth "ping-pong" or "breathing" effect without needing to manually code the return journey in your @keyframes.

✅ animation-fill-mode – forwards, backwards, both

animation-fill-mode determines what styles the element holds outside the animation's active time — before it starts (during a delay) and after it finishes. Without this, elements snap back to their original styles the moment the animation ends.

fill-mode: none vs forwards
.no-fill {
  animation-fill-mode: none; /* snaps back */
}

.with-forwards {
  animation-fill-mode: forwards; /* stays at end */
}
👁 Both run once. Watch what happens after.
none
snaps back
forwards
stays in place
⚠️ Most common oversight: Forgetting animation-fill-mode: forwards; on a one-time entrance animation (like a fade-in or slide-in) causes the element to snap back to invisible or off-screen the moment the animation finishes — the single most jarring mistake in CSS animation.

✅ animation-play-state – Running & Paused

animation-play-state toggles an animation between running and paused — the animation freezes exactly where it is and resumes from the same point. This is commonly triggered via CSS :hover or a JavaScript class toggle.

animation-play-state – Hover to Pause
.spinner {
  animation: spin 1.4s linear infinite;
  animation-play-state: running;
}

.spinner:hover {
  animation-play-state: paused;
}
👁 Hover to pause the spin
⏸ hover

✅ The animation Shorthand

The animation shorthand combines all eight animation properties into one compact declaration. The order is: name duration timing-function delay iteration-count direction fill-mode play-state.

/* Longhand */
.box {
  animation-name: slidein;
  animation-duration: 0.6s;
  animation-timing-function: ease-out;
  animation-delay: 0.2s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-play-state: running;
}

/* Shorthand — identical result */
.box {
  animation: slidein 0.6s ease-out 0.2s 1 normal forwards running;
}

/* Most common everyday form (omitting defaults) */
.box {
  animation: slidein 0.6s ease-out forwards;
}
💡 Pro Tip: You can apply multiple animations to one element by comma-separating them: animation: spin 1s linear infinite, pulse 2s ease-in-out infinite; — both run simultaneously and independently.

✅ Real-World Animation Patterns

Here are the six most commonly used CSS animation patterns in production UI — all running live:

Spinner / Loader
pulse
Attention Pulse
Bounce
fade-in
Fade In / Up
color
Color Cycle
Typewriter...
Typewriter

✅ Animation Properties – Reference Table

PropertyValues / ExampleWhat It Controls
@keyframes name { }from/to or 0%–100%Defines the animation steps by name
animation-nameslidein · noneLinks element to a @keyframes rule
animation-duration0.6s · 400msHow long one full cycle takes
animation-timing-functionease · linear · ease-in · ease-out · ease-in-out · cubic-bezier()Speed curve across the duration
animation-delay0.3s · -0.5sWait time before the animation starts
animation-iteration-count1 · 3 · infiniteNumber of times the cycle repeats
animation-directionnormal · reverse · alternate · alternate-reverseWhich direction through @keyframes each cycle runs
animation-fill-modenone · forwards · backwards · bothStyles applied before start / after end
animation-play-staterunning · pausedToggle play / pause without resetting
animation (shorthand)name duration timing delay count dir fill stateCombines all eight properties

✅ Best Practices

✔️ 1) Animate only transform and opacity for Maximum Performance
Browsers can run transform and opacity animations on the GPU compositor thread, giving smooth 60fps with near-zero CPU cost. Animating layout-affecting properties like width, height, top, or margin forces full layout recalculations on every frame and can cause jank.

✔️ 2) Always Add animation-fill-mode: forwards on One-Time Entrance Animations
Without it, the element snaps back to its pre-animation state the moment the animation finishes — which is almost never what you want for a fade-in or slide-in effect.

✔️ 3) Respect prefers-reduced-motion
Wrap all non-essential animations in a @media (prefers-reduced-motion: reduce) block and disable or tone them down — motion can cause discomfort for users with vestibular disorders.

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

✔️ 4) Use animation-delay for Staggered Entrance Effects
Incrementing delay values across list items (0s, 0.1s, 0.2s…) creates a cascade that feels polished and natural with zero extra @keyframes or JavaScript.

✔️ 5) Keep animation-duration Under 600ms for UI Feedback
Animations faster than 600ms feel responsive; longer than 1–2 seconds feel sluggish for interactive UI. Save longer durations for background decorative animations where the user isn't waiting.

💡 Pro Tip: Store animation tokens as CSS custom properties — --anim-duration: 0.4s; --anim-easing: ease-out; — so the entire site's motion feel can be adjusted by changing just two variables.

✅ Common Mistakes to Avoid

❌ Mistake 1 – Mismatched @keyframes Name
The name in animation-name must match the @keyframes identifier exactly, including case. A single typo silently kills the entire animation with no error message.
❌ Mistake 2 – Forgetting animation-fill-mode: forwards on Entrance Animations
The most visually jarring bug in CSS animation — a fade-in or slide-in that snaps back to invisible the moment it finishes. Always set fill-mode: forwards on one-time entrance effects.
❌ Mistake 3 – Animating Layout Properties Instead of transform
Animating left, top, width, or margin triggers full layout recalculation every frame — causing janky, low-FPS animation. Always use transform: translate(), scale() etc. instead.
❌ Mistake 4 – Setting animation-duration to 0s
A zero duration makes the animation play instantaneously — the @keyframes rule runs but the visual result looks like a snap, not a motion.
❌ Mistake 5 – Ignoring prefers-reduced-motion
Spinning, bouncing, and flashing animations can cause real discomfort for users with vestibular disorders or motion sensitivity. Always provide a reduced-motion fallback.

✅ Complete Live Example

A notification toast that slides in from the right, pauses to be read, then fades out — all with CSS animations only:

Notification Toast Animation – Live Preview
@keyframes toast-in {
  from { transform: translateX(120%); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

.toast {
  animation: toast-in 0.5s ease-out forwards;
}
👁 Notification Toast (loops for preview)
✅ Changes saved successfully!

✅ Try It Yourself – Interactive Editor

Edit the HTML and CSS below to experiment with CSS animations. Try changing @keyframes steps, the timing function, iteration count, or fill-mode. The preview updates automatically.

🖥 Interactive CSS Animations Editor
👁 Live Preview

✅ 🎨 Interactive Animation Builder

Pick a motion type, then dial in duration, timing function, delay, iteration count, direction, and fill-mode to generate ready-to-use CSS animation code.

🎨 CSS Animation Builder
BOX
Generated CSS
/* Generated CSS will appear here */

✅ Practice – Yes / No Quiz

1. Are animation-name and animation-duration the only two properties required to run a CSS animation?

2. Does animation-fill-mode: forwards make an element snap back to its original style after the animation ends?

3. Does animation-direction: alternate make the animation play forward then backward on each cycle?

4. Is animating the CSS left and top properties recommended for best animation performance?

5. Can animation-play-state pause a CSS animation exactly where it is and resume from the same point?

0/5
Your Score – Keep Practising! 🎯

✅ Frequently Asked Questions (FAQ)

What is the difference between CSS transitions and CSS animations?
CSS transitions run automatically when a CSS property changes from one value to another, triggered by things like :hover or a JavaScript class change. CSS animations run on their own, driven by a @keyframes rule that defines multiple steps, and can loop, reverse, delay, and run without any user interaction or property change trigger.
What is @keyframes in CSS?
@keyframes is an at-rule that defines the steps of a CSS animation by name. Each step is described using either 'from' and 'to' keywords (for a simple two-step animation) or percentage values (0%, 25%, 100%, etc.) for more complex multi-step sequences. Once defined, the @keyframes rule is linked to an element by its name using the animation-name property.
What does animation-fill-mode: forwards do?
Without animation-fill-mode: forwards, an element snaps back to its original pre-animation styles as soon as the animation finishes. Setting it to forwards tells the browser to keep the styles from the final keyframe applied even after the animation ends — this is essential for entrance animations like fade-in or slide-in where you want the element to stay visible after it arrives.
What is the difference between ease, ease-in, ease-out and linear?
linear maintains a perfectly constant speed throughout. ease starts slow, speeds up in the middle, then slows again at the end. ease-in starts slowly and accelerates toward the end. ease-out starts fast and decelerates toward the end. ease-in-out combines a slow start and a slow end with faster speed in the middle — similar to ease but with a more symmetric acceleration curve.
How do I pause and resume a CSS animation with JavaScript?
Toggle the animation-play-state CSS property between 'running' and 'paused' — either directly in a CSS class you add and remove with JavaScript, or by setting element.style.animationPlayState = 'paused' and 'running' in script. The animation freezes exactly where it was when paused and resumes from that same point when switched back to running.
Can I animate multiple properties in a single @keyframes rule?
Yes. A single @keyframes step can list any number of CSS properties at once — for example, both opacity and transform can be changed in the same 50% keyframe step, and the browser blends all of them simultaneously across the animation cycle.
✍️ About the Author – Pramod Behera

Pramod Behera is the founder of LearnToSAP.com and an experienced web development educator. He creates beginner-friendly tutorials on HTML, CSS, SAP SD/MM, and frontend development, helping thousands of learners worldwide build practical skills.