CSS 55 ๐ป animation property
The animation property is one of the most powerful tools in CSS. It lets you create complex, multi-step animations โ with full control over timing, repetition, direction, and more.
What is an Animation?
An animation in CSS is defined by two parts:
@keyframesโ defines the stages of the animationanimationproperty โ applies the animation to an element
Unlike transitions (which animate between two states), animations can have many stages and run automatically without user interaction.
The animation Shorthand
The animation property is a shorthand for 8 individual animation properties:
| Property | Description | Default |
|---|---|---|
animation-name | Name of the @keyframes rule | none |
animation-duration | How long one cycle takes | 0s |
animation-timing-function | Speed curve | ease |
animation-delay | Wait before starting | 0s |
animation-iteration-count | How many times to repeat | 1 |
animation-direction | Direction of each cycle | normal |
animation-fill-mode | Styles before/after animation | none |
animation-play-state | Running or paused | running |
Syntax
animation: name duration timing-function delay iteration-count direction fill-mode play-state;
Only name and duration are required. All other values are optional.
The @keyframes Rule
The @keyframes rule defines the stages of an animation.
@keyframes exampleAnimation {
0% { background-color: red; transform: scale(1); }
50% { background-color: blue; transform: scale(1.5); }
100% { background-color: green; transform: scale(1); }
}
Syntax Options
Using from and to:
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Using percentages:
@keyframes bounce {
0% { transform: translateY(0); }
50% { transform: translateY(-50px); }
100% { transform: translateY(0); }
}
| Keyword | Equivalent |
|---|---|
from | 0% |
to | 100% |
Individual Animation Properties
1. animation-name
The name of the @keyframes rule to use.
animation-name: exampleAnimation;
2. animation-duration
How long one cycle of the animation takes.
animation-duration: 4s;
3. animation-timing-function
The speed curve of the animation.
animation-timing-function: ease-in-out;
| Value | Description |
|---|---|
ease | Slow start, fast middle, slow end (default) |
linear | Constant speed |
ease-in | Slow start, fast end |
ease-out | Fast start, slow end |
ease-in-out | Slow start, fast middle, slow end |
cubic-bezier(n,n,n,n) | Custom curve |
steps(n) | Stepped animation |
4. animation-delay
How long to wait before starting the animation.
animation-delay: 2s;
5. animation-iteration-count
How many times the animation repeats.
animation-iteration-count: infinite; /* or a number */
| Value | Description |
|---|---|
1 | Plays once (default) |
3 | Plays 3 times |
infinite | Repeats forever |
6. animation-direction
The direction of each cycle.
animation-direction: alternate;
| Value | Description |
|---|---|
normal | Forward each cycle (default) |
reverse | Backward each cycle |
alternate | Forward, then backward |
alternate-reverse | Backward, then forward |
7. animation-fill-mode
What styles apply before and after the animation.
animation-fill-mode: forwards;
| Value | Description |
|---|---|
none | No styles applied outside the animation (default) |
forwards | Keep the last keyframe’s styles |
backwards | Apply the first keyframe’s styles during delay |
both | Apply both forwards and backwards |
8. animation-play-state
Whether the animation is running or paused.
animation-play-state: paused;
| Value | Description |
|---|---|
running | Animation is playing (default) |
paused | Animation is paused |
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The animation Property</title>
<style>
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
padding: 20px;
background: #f8f9fa;
color: #333;
max-width: 1200px;
margin: 0 auto;
line-height: 1.6;
}
h1 {
color: #007bff;
border-bottom: 3px solid #007bff;
padding-bottom: 10px;
}
h2 {
color: #28a745;
border-left: 4px solid #28a745;
padding-left: 15px;
margin-top: 30px;
}
h3 {
color: #333;
margin-top: 20px;
}
section {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin: 20px 0;
}
.code-block {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.8;
margin: 10px 0;
}
.reference-table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
.reference-table th,
.reference-table td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
.reference-table th {
background: #007bff;
color: white;
}
.reference-table tr:nth-child(even) {
background: #f8f9fa;
}
.note {
font-size: 0.9rem;
color: #6c757d;
margin-top: 5px;
}
.highlight {
background: #ffc107;
color: #333;
padding: 2px 6px;
border-radius: 4px;
font-weight: bold;
}
/* ====== DEMO AREA ====== */
.demo-area {
display: flex;
flex-wrap: wrap;
gap: 40px;
justify-content: center;
align-items: center;
padding: 40px 20px;
background: #e9ecef;
border-radius: 8px;
margin: 15px 0;
min-height: 200px;
overflow: hidden;
}
/* ====== BASIC ANIMATION ====== */
.animation-example {
width: 100px;
height: 100px;
background-color: #dc3545;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
animation-name: exampleAnimation;
animation-duration: 4s;
animation-timing-function: ease-in-out;
animation-delay: 2s;
animation-iteration-count: infinite;
}
@keyframes exampleAnimation {
0% { background-color: #dc3545; transform: scale(1); }
50% { background-color: #007bff; transform: scale(1.5); }
100% { background-color: #28a745; transform: scale(1); }
}
/* ====== SHORTHAND ====== */
.animation-shorthand {
width: 100px;
height: 100px;
background: #6c5ce7;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
animation: bounce 2s ease-in-out infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-40px); }
}
/* ====== FADE IN ====== */
.fade-in {
width: 100px;
height: 100px;
background: #28a745;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
animation: fadeIn 2s ease forwards;
opacity: 0;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* ====== SLIDE IN ====== */
.slide-in {
width: 100px;
height: 100px;
background: #ffc107;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: #333;
font-weight: bold;
animation: slideIn 1.5s ease-out forwards;
transform: translateX(-200px);
}
@keyframes slideIn {
from { transform: translateX(-200px); }
to { transform: translateX(0); }
}
/* ====== PULSE ====== */
.pulse {
width: 100px;
height: 100px;
background: #dc3545;
border-radius: 50%;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
70% { transform: scale(1.1); box-shadow: 0 0 0 20px rgba(220, 53, 69, 0); }
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
}
/* ====== ROTATE ====== */
.rotate {
width: 100px;
height: 100px;
background: #17a2b8;
border-radius: 12px;
animation: rotate 3s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* ====== SPINNER ====== */
.spinner {
width: 60px;
height: 60px;
border: 6px solid #e9ecef;
border-top: 6px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* ====== MULTI-STEP ====== */
.multi-step {
width: 100px;
height: 100px;
background: #007bff;
border-radius: 12px;
animation: multiStep 4s ease-in-out infinite;
}
@keyframes multiStep {
0% { background: #007bff; transform: translate(0, 0) rotate(0deg); }
25% { background: #28a745; transform: translate(100px, 0) rotate(90deg); }
50% { background: #ffc107; transform: translate(100px, 100px) rotate(180deg); }
75% { background: #dc3545; transform: translate(0, 100px) rotate(270deg); }
100% { background: #007bff; transform: translate(0, 0) rotate(360deg); }
}
/* ====== DIRECTION COMPARISON ====== */
.direction-box {
width: 80px;
height: 80px;
background: #6c5ce7;
border-radius: 12px;
animation-duration: 2s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
.direction-normal {
animation-name: slideAcross;
animation-direction: normal;
}
.direction-reverse {
animation-name: slideAcross;
animation-direction: reverse;
}
.direction-alternate {
animation-name: slideAcross;
animation-direction: alternate;
}
.direction-alternate-reverse {
animation-name: slideAcross;
animation-direction: alternate-reverse;
}
@keyframes slideAcross {
from { transform: translateX(0); background: #6c5ce7; }
to { transform: translateX(150px); background: #28a745; }
}
/* ====== FILL MODE COMPARISON ====== */
.fill-box {
width: 80px;
height: 80px;
background: #007bff;
border-radius: 12px;
animation-duration: 2s;
animation-delay: 1s;
animation-timing-function: ease;
animation-fill-mode: none;
animation-name: fillDemo;
opacity: 0;
}
.fill-none {
animation-fill-mode: none;
}
.fill-forwards {
animation-fill-mode: forwards;
}
.fill-backwards {
animation-fill-mode: backwards;
}
.fill-both {
animation-fill-mode: both;
}
@keyframes fillDemo {
from { opacity: 0; transform: translateX(-50px); background: #dc3545; }
to { opacity: 1; transform: translateX(0); background: #28a745; }
}
/* ====== PLAY STATE ====== */
.play-pause-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
}
.play-pause-box {
width: 100px;
height: 100px;
background: #ffc107;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: #333;
font-weight: bold;
animation: pulse 1.5s ease-in-out infinite;
}
.play-pause-box:hover {
animation-play-state: paused;
}
/* ====== PRACTICAL: LOADING SKELETON ====== */
.skeleton-container {
max-width: 400px;
margin: 15px auto;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.skeleton-line {
height: 16px;
background: linear-gradient(90deg, #e9ecef 25%, #f8f9fa 50%, #e9ecef 75%);
background-size: 200% 100%;
border-radius: 8px;
margin-bottom: 12px;
animation: shimmer 1.5s infinite;
}
.skeleton-line.short {
width: 60%;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* ====== PRACTICAL: BUTTON LOADING ====== */
.btn-loading {
padding: 15px 35px;
background: #007bff;
color: white;
border: none;
border-radius: 8px;
font-size: 1em;
font-weight: bold;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 10px;
margin: 10px;
}
.btn-loading .dot {
width: 8px;
height: 8px;
background: white;
border-radius: 50%;
animation: dotPulse 1.4s ease-in-out infinite;
}
.btn-loading .dot:nth-child(2) {
animation-delay: 0.2s;
}
.btn-loading .dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes dotPulse {
0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
40% { transform: scale(1); opacity: 1; }
}
/* ====== PRACTICAL: FLOATING ELEMENTS ====== */
.float-container {
display: flex;
gap: 30px;
justify-content: center;
margin: 20px 0;
}
.float-item {
width: 80px;
height: 80px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
animation: float 3s ease-in-out infinite;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
.float-item:nth-child(1) { background: #007bff; animation-delay: 0s; }
.float-item:nth-child(2) { background: #28a745; animation-delay: 0.3s; }
.float-item:nth-child(3) { background: #ffc107; animation-delay: 0.6s; }
.float-item:nth-child(4) { background: #dc3545; animation-delay: 0.9s; }
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
/* ====== TIPS ====== */
.tip-box {
padding: 15px;
border-radius: 8px;
margin: 10px 0;
border-left: 4px solid #007bff;
background: #f8f9fa;
}
.tip-box.success { border-left-color: #28a745; }
.tip-box.warning { border-left-color: #ffc107; }
.tip-box.danger { border-left-color: #dc3545; }
</style>
</head>
<body>
<h1>The animation Property</h1>
<!-- ====== 1. BASIC ANIMATION ====== -->
<section>
<h2>1. Basic Animation</h2>
<p>This box animates through three colors and scales using all individual properties.</p>
<div class="demo-area">
<div class="animation-example"></div>
</div>
<div class="code-block">
.animation-example {
animation-name: exampleAnimation;
animation-duration: 4s;
animation-timing-function: ease-in-out;
animation-delay: 2s;
animation-iteration-count: infinite;
}
@keyframes exampleAnimation {
0% { background-color: red; transform: scale(1); }
50% { background-color: blue; transform: scale(1.5); }
100% { background-color: green; transform: scale(1); }
}
</div>
</section>
<!-- ====== 2. SHORTHAND ====== -->
<section>
<h2>2. animation Shorthand</h2>
<p>The shorthand combines all animation properties into one declaration.</p>
<div class="demo-area">
<div class="animation-shorthand"></div>
</div>
<div class="code-block">
/* Shorthand: name duration timing-function delay iteration-count direction fill-mode play-state */
.animation-shorthand {
animation: bounce 2s ease-in-out infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-40px); }
}
</div>
</section>
<!-- ====== 3. COMMON ANIMATIONS ====== -->
<section>
<h2>3. Common Animation Patterns</h2>
<h3>Fade In</h3>
<div class="demo-area">
<div class="fade-in">Fade In</div>
</div>
<div class="code-block">
.fade-in {
animation: fadeIn 2s ease forwards;
opacity: 0;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</div>
<h3>Slide In</h3>
<div class="demo-area">
<div class="slide-in">Slide In</div>
</div>
<div class="code-block">
.slide-in {
animation: slideIn 1.5s ease-out forwards;
transform: translateX(-200px);
}
@keyframes slideIn {
from { transform: translateX(-200px); }
to { transform: translateX(0); }
}
</div>
<h3>Pulse</h3>
<div class="demo-area">
<div class="pulse"></div>
</div>
<div class="code-block">
.pulse {
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
70% { transform: scale(1.1); box-shadow: 0 0 0 20px rgba(220, 53, 69, 0); }
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
}
</div>
<h3>Rotate</h3>
<div class="demo-area">
<div class="rotate"></div>
</div>
<div class="code-block">
.rotate {
animation: rotate 3s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</div>
<h3>Spinner</h3>
<div class="demo-area">
<div class="spinner"></div>
</div>
<div class="code-block">
.spinner {
border: 6px solid #e9ecef;
border-top: 6px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</div>
</section>
<!-- ====== 4. MULTI-STEP ANIMATION ====== -->
<section>
<h2>4. Multi-Step Animation</h2>
<p>This box travels in a square pattern using multiple keyframes.</p>
<div class="demo-area" style="min-height: 300px;">
<div class="multi-step"></div>
</div>
<div class="code-block">
.multi-step {
animation: multiStep 4s ease-in-out infinite;
}
@keyframes multiStep {
0% { background: #007bff; transform: translate(0, 0) rotate(0deg); }
25% { background: #28a745; transform: translate(100px, 0) rotate(90deg); }
50% { background: #ffc107; transform: translate(100px, 100px) rotate(180deg); }
75% { background: #dc3545; transform: translate(0, 100px) rotate(270deg); }
100% { background: #007bff; transform: translate(0, 0) rotate(360deg); }
}
</div>
</section>
<!-- ====== 5. ANIMATION DIRECTION ====== -->
<section>
<h2>5. animation-direction</h2>
<p>Compare the four direction values.</p>
<div class="demo-area" style="flex-direction: column; gap: 20px; align-items: flex-start;">
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 180px;">normal:</span>
<div class="direction-box direction-normal"></div>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 180px;">reverse:</span>
<div class="direction-box direction-reverse"></div>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 180px;">alternate:</span>
<div class="direction-box direction-alternate"></div>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 180px;">alternate-reverse:</span>
<div class="direction-box direction-alternate-reverse"></div>
</div>
</div>
<div class="code-block">
.direction-normal { animation-direction: normal; }
.direction-reverse { animation-direction: reverse; }
.direction-alternate { animation-direction: alternate; }
.direction-alternate-reverse { animation-direction: alternate-reverse; }
@keyframes slideAcross {
from { transform: translateX(0); background: #6c5ce7; }
to { transform: translateX(150px); background: #28a745; }
}
</div>
</section>
<!-- ====== 6. ANIMATION FILL MODE ====== -->
<section>
<h2>6. animation-fill-mode</h2>
<p>Compare how styles apply before and after the animation.</p>
<div class="demo-area" style="flex-direction: column; gap: 20px; align-items: flex-start;">
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 150px;">none:</span>
<div class="fill-box fill-none"></div>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 150px;">forwards:</span>
<div class="fill-box fill-forwards"></div>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 150px;">backwards:</span>
<div class="fill-box fill-backwards"></div>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-weight: bold; min-width: 150px;">both:</span>
<div class="fill-box fill-both"></div>
</div>
</div>
<div class="code-block">
.fill-none { animation-fill-mode: none; }
.fill-forwards { animation-fill-mode: forwards; }
.fill-backwards { animation-fill-mode: backwards; }
.fill-both { animation-fill-mode: both; }
@keyframes fillDemo {
from { opacity: 0; transform: translateX(-50px); background: #dc3545; }
to { opacity: 1; transform: translateX(0); background: #28a745; }
}
</div>
<p class="note"><strong>forwards</strong> keeps the end state, <strong>backwards</strong> applies the start state during delay, and <strong>both</strong> does both.</p>
</section>
<!-- ====== 7. ANIMATION PLAY STATE ====== -->
<section>
<h2>7. animation-play-state</h2>
<p>Hover over the box to pause the animation.</p>
<div class="demo-area">
<div class="play-pause-container">
<div class="play-pause-box">Hover to Pause</div>
</div>
</div>
<div class="code-block">
.play-pause-box {
animation: pulse 1.5s ease-in-out infinite;
}
.play-pause-box:hover {
animation-play-state: paused;
}
</div>
</section>
<!-- ====== 8. PRACTICAL: LOADING SKELETON ====== -->
<section>
<h2>8. Practical Example: Loading Skeleton</h2>
<p>A shimmer effect commonly used in loading placeholders.</p>
<div class="skeleton-container">
<div class="skeleton-line"></div>
<div class="skeleton-line"></div>
<div class="skeleton-line short"></div>
</div>
<div class="code-block">
.skeleton-line {
background: linear-gradient(90deg, #e9ecef 25%, #f8f9fa 50%, #e9ecef 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
</div>
</section>
<!-- ====== 9. PRACTICAL: BUTTON LOADING ====== -->
<section>
<h2>9. Practical Example: Button Loading Dots</h2>
<p>Animated dots for a loading button.</p>
<div style="text-align: center;">
<button class="btn-loading">
Loading
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</button>
</div>
<div class="code-block">
.btn-loading .dot {
width: 8px;
height: 8px;
background: white;
border-radius: 50%;
animation: dotPulse 1.4s ease-in-out infinite;
}
.btn-loading .dot:nth-child(2) { animation-delay: 0.2s; }
.btn-loading .dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes dotPulse {
0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
40% { transform: scale(1); opacity: 1; }
}
</div>
</section>
<!-- ====== 10. PRACTICAL: FLOATING ELEMENTS ====== -->
<section>
<h2>10. Practical Example: Floating Elements</h2>
<p>Staggered floating animation with different delays.</p>
<div class="float-container">
<div class="float-item">๐</div>
<div class="float-item">โญ</div>
<div class="float-item">๐ฏ</div>
<div class="float-item">๐</div>
</div>
<div class="code-block">
.float-item {
animation: float 3s ease-in-out infinite;
}
.float-item:nth-child(1) { animation-delay: 0s; }
.float-item:nth-child(2) { animation-delay: 0.3s; }
.float-item:nth-child(3) { animation-delay: 0.6s; }
.float-item:nth-child(4) { animation-delay: 0.9s; }
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
</div>
</section>
<!-- ====== 11. REFERENCE TABLES ====== -->
<section>
<h2>11. Reference Tables</h2>
<h3>Animation Properties</h3>
<table class="reference-table">
<tr>
<th>Property</th>
<th>Description</th>
<th>Default</th>
</tr>
<tr>
<td><code>animation-name</code></td>
<td>Name of the @keyframes rule</td>
<td><code>none</code></td>
</tr>
<tr>
<td><code>animation-duration</code></td>
<td>How long one cycle takes</td>
<td><code>0s</code></td>
</tr>
<tr>
<td><code>animation-timing-function</code></td>
<td>Speed curve</td>
<td><code>ease</code></td>
</tr>
<tr>
<td><code>animation-delay</code></td>
<td>Wait before starting</td>
<td><code>0s</code></td>
</tr>
<tr>
<td><code>animation-iteration-count</code></td>
<td>How many times to repeat</td>
<td><code>1</code></td>
</tr>
<tr>
<td><code>animation-direction</code></td>
<td>Direction of each cycle</td>
<td><code>normal</code></td>
</tr>
<tr>
<td><code>animation-fill-mode</code></td>
<td>Styles before/after animation</td>
<td><code>none</code></td>
</tr>
<tr>
<td><code>animation-play-state</code></td>
<td>Running or paused</td>
<td><code>running</code></td>
</tr>
</table>
<h3>animation-direction Values</h3>
<table class="reference-table">
<tr>
<th>Value</th>
<th>Description</th>
</tr>
<tr>
<td><code>normal</code></td>
<td>Forward each cycle (default)</td>
</tr>
<tr>
<td><code>reverse</code></td>
<td>Backward each cycle</td>
</tr>
<tr>
<td><code>alternate</code></td>
<td>Forward, then backward</td>
</tr>
<tr>
<td><code>alternate-reverse</code></td>
<td>Backward, then forward</td>
</tr>
</table>
<h3>animation-fill-mode Values</h3>
<table class="reference-table">
<tr>
<th>Value</th>
<th>Description</th>
</tr>
<tr>
<td><code>none</code></td>
<td>No styles applied outside the animation (default)</td>
</tr>
<tr>
<td><code>forwards</code></td>
<td>Keep the last keyframe's styles</td>
</tr>
<tr>
<td><code>backwards</code></td>
<td>Apply the first keyframe's styles during delay</td>
</tr>
<tr>
<td><code>both</code></td>
<td>Apply both forwards and backwards</td>
</tr>
</table>
<h3>@keyframes Syntax</h3>
<table class="reference-table">
<tr>
<th>Syntax</th>
<th>Description</th>
</tr>
<tr>
<td><code>from { }</code></td>
<td>Equivalent to <code>0%</code></td>
</tr>
<tr>
<td><code>to { }</code></td>
<td>Equivalent to <code>100%</code></td>
</tr>
<tr>
<td><code>50% { }</code></td>
<td>Halfway through the animation</td>
</tr>
</table>
</section>
<!-- ====== 12. BEST PRACTICES ====== -->
<section>
<h2>12. Best Practices</h2>
<div style="background: #d4edda; padding: 20px; border-radius: 8px; border-left: 4px solid #28a745;">
<h3 style="margin-top: 0; color: #155724;">โ
Do This:</h3>
<ul>
<li>Use <code>transform</code> and <code>opacity</code> for smooth, hardware-accelerated animations</li>
<li>Use the shorthand <code>animation</code> for cleaner code</li>
<li>Use <code>animation-fill-mode: forwards</code> to keep the end state</li>
<li>Use <code>animation-delay</code> for staggered effects</li>
<li>Use <code>infinite</code> for continuous animations (loading spinners)</li>
<li>Respect <code>prefers-reduced-motion</code> for accessibility</li>
<li>Keep animations short and purposeful</li>
</ul>
</div>
<div style="background: #f8d7da; padding: 20px; border-radius: 8px; border-left: 4px solid #dc3545; margin-top: 15px;">
<h3 style="margin-top: 0; color: #721c24;">โ Don't Do This:</h3>
<ul>
<li>Don't animate layout properties (<code>width</code>, <code>height</code>, <code>top</code>, <code>left</code>)</li>
<li>Don't use <code>infinite</code> animations that distract from content</li>
<li>Don't forget to specify <code>animation-duration</code> (default is 0s โ no animation!)</li>
<li>Don't use animations for critical functionality that must work without them</li>
<li>Don't overuse animations โ a few well-placed ones are better than many</li>
<li>Don't forget about <code>prefers-reduced-motion</code></li>
</ul>
</div>
<div class="code-block">
/* Accessibility: respect reduced motion */
@media (prefers-reduced-motion: reduce) {
.animation-example,
.bounce,
.pulse,
.rotate,
.spinner,
.float-item {
animation: none;
}
}
/* Best practice: use transform and opacity */
.smooth {
animation: slideIn 1s ease forwards;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</div>
</section>
</body>
</html>
Quick Reference
| Property | Description | Default |
|---|---|---|
animation-name | Name of the @keyframes rule | none |
animation-duration | How long one cycle takes | 0s |
animation-timing-function | Speed curve | ease |
animation-delay | Wait before starting | 0s |
animation-iteration-count | How many times to repeat | 1 |
animation-direction | Direction of each cycle | normal |
animation-fill-mode | Styles before/after animation | none |
animation-play-state | Running or paused | running |
animation-direction Values
| Value | Description |
|---|---|
normal | Forward each cycle (default) |
reverse | Backward each cycle |
alternate | Forward, then backward |
alternate-reverse | Backward, then forward |
animation-fill-mode Values
| Value | Description |
|---|---|
none | No styles applied outside the animation (default) |
forwards | Keep the last keyframe’s styles |
backwards | Apply the first keyframe’s styles during delay |
both | Apply both forwards and backwards |
@keyframes Syntax
| Syntax | Description |
|---|---|
from { } | Equivalent to 0% |
to { } | Equivalent to 100% |
50% { } | Halfway through the animation |
Best Practices
โ Do This:
/* Simple bounce animation */
.bounce {
animation: bounce 1s ease infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
/* Fade in and stay visible */
.fade-in {
animation: fadeIn 1s ease forwards;
opacity: 0;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Staggered animation */
.item:nth-child(1) { animation-delay: 0s; }
.item:nth-child(2) { animation-delay: 0.1s; }
.item:nth-child(3) { animation-delay: 0.2s; }
/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
.bounce, .fade-in {
animation: none;
}
}
โ Don’t Do This:
/* Don't forget animation-duration */
.box {
animation-name: bounce; /* Duration is 0s by default โ no animation! */
}
/* Don't animate layout properties */
.box {
animation: moveBox 1s infinite;
}
@keyframes moveBox {
from { left: 0; }
to { left: 100px; } /* Causes layout recalculation */
}
/* Don't overuse infinite animations */
.everything {
animation: spin 1s infinite; /* Distracting */
}
Pro Tip: CSS animations are perfect for attention-grabbing effects (loading spinners, notifications), entrance animations (fade in, slide in), and continuous ambient effects (floating, pulsing). Use transform and opacity for the smoothest animations โ they’re hardware-accelerated. Remember: animation-duration is required (default 0s means no animation). Use animation-fill-mode: forwards to keep the end state. And always respect prefers-reduced-motion โ some users are sensitive to motion and may experience discomfort from animations!
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!