CSS Transitions & Animations
CSS transitions and animations create smooth, engaging user experiences without JavaScript.
Transitions
Animate property changes smoothly:
.button {
background-color: #3498db;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #2980b9;
}
Transition Properties
/* Shorthand */
transition: property duration timing-function delay;
/* Full syntax */
transition-property: background-color;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s;
Timing Functions
transition-timing-function: ease; /* Slow start/end */
transition-timing-function: ease-in; /* Slow start */
transition-timing-function: ease-out; /* Slow end */
transition-timing-function: ease-in-out; /* Slow start/end */
transition-timing-function: linear; /* Constant speed */
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); /* Custom */
Multiple Transitions
.button {
transition:
background-color 0.3s ease,
transform 0.2s ease,
box-shadow 0.3s ease;
}
.button:hover {
background-color: #2980b9;
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
Transforms
Move, rotate, scale, and skew elements:
/* Translate (move) */
.transform {
transform: translateX(100px);
transform: translateY(-50px);
transform: translate(100px, -50px);
}
/* Rotate */
.transform {
transform: rotate(45deg);
transform: rotate(-90deg);
}
/* Scale */
.transform {
transform: scale(1.5);
transform: scale(0.8);
transform: scaleX(2);
transform: scaleY(0.5);
}
/* Skew */
.transform {
transform: skew(10deg);
transform: skewX(10deg);
transform: skewY(-5deg);
}
/* Multiple transforms */
.transform {
transform: translate(100px, 50px) rotate(45deg) scale(1.5);
}
Transform Origin
transform-origin: center; /* Default */
transform-origin: top left;
transform-origin: 50% 50%;
transform-origin: 0 0;
Keyframe Animations
Define complex animations:
/* Define animation */
@keyframes slide-in {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* Apply animation */
.element {
animation: slide-in 0.5s ease;
}
Animation Properties
/* Shorthand */
animation: name duration timing-function delay iteration-count direction fill-mode;
/* Full syntax */
animation-name: slide-in;
animation-duration: 0.5s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: running;
Animation Iteration
/* Infinite animation */
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite;
}
/* Multiple iterations */
.bounce {
animation: bounce 0.5s ease 3;
}
Animation Direction
animation-direction: normal; /* Forward */
animation-direction: reverse; /* Backward */
animation-direction: alternate; /* Forward then backward */
animation-direction: alternate-reverse; /* Backward then forward */
Animation Fill Mode
animation-fill-mode: none; /* Default */
animation-fill-mode: forwards; /* Stay at end state */
animation-fill-mode: backwards; /* Start at first keyframe */
animation-fill-mode: both; /* Both forwards and backwards */
Complete Examples
Loading Spinner
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
Pulse Animation
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 2s ease infinite;
}
Slide In from Left
@keyframes slideInLeft {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.slide-in {
animation: slideInLeft 0.5s ease forwards;
}
Fade In Up
@keyframes fadeInUp {
from {
transform: translateY(20px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.fade-in-up {
animation: fadeInUp 0.6s ease forwards;
}
Shake Animation
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.shake {
animation: shake 0.5s ease;
}
Complete Example: Animated Card
.card {
background: white;
border-radius: 10px;
padding: 1.5rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
transition:
transform 0.3s ease,
box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-10px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
.card-image {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 5px;
transition: transform 0.3s ease;
}
.card:hover .card-image {
transform: scale(1.05);
}
Complete Example: Page Transitions
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from {
transform: translateY(30px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.page {
animation: fadeIn 0.5s ease;
}
.content > * {
animation: slideUp 0.5s ease forwards;
opacity: 0;
}
.content > *:nth-child(1) { animation-delay: 0.1s; }
.content > *:nth-child(2) { animation-delay: 0.2s; }
.content > *:nth-child(3) { animation-delay: 0.3s; }
Performance Tips
- Animate transform and opacity — GPU accelerated
- Avoid animating width/height — Causes layout recalculation
- Use will-change sparingly — Hints browser about changes
- Keep animations short — 300-500ms is ideal
- Use requestAnimationFrame — For JavaScript animations
Best Practices
- Use transitions for simple hover effects
- Use keyframes for complex animations
- Test on mobile — Some animations cause motion sickness
- Respect prefers-reduced-motion — Accessibility
- Don’t overuse animations — Can be distracting
Common Mistakes
- Animating layout properties — Width, height, margin cause jank
- Too many animations — Overwhelming for users
- Ignoring accessibility — Some users need reduced motion
- Using !important on animations — Hard to override
- Not testing performance — Animations should be smooth 60fps