Day 9: Transitions and Animations
What You Will Learn Today
- CSS transitions for smooth property changes
- Timing functions and how they affect motion
- The
transformproperty @keyframesanimations for complex sequences- Common animation patterns
- Performance considerations
- Accessibility with
prefers-reduced-motion
CSS Transitions
A transition smoothly interpolates between two states of a property when it changes.
.button {
background-color: #3b82f6;
color: white;
padding: 12px 24px;
border: none;
border-radius: 8px;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #1d4ed8;
}
The transition Property
/* Individual properties */
transition-property: background-color;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s;
/* Shorthand */
transition: background-color 0.3s ease 0s;
/* Multiple properties */
transition: background-color 0.3s ease, transform 0.2s ease;
/* All animatable properties */
transition: all 0.3s ease;
Timing Functions
| Value | Behavior |
|---|---|
ease |
Slow start, fast middle, slow end (default) |
ease-in |
Slow start |
ease-out |
Slow end |
ease-in-out |
Slow start and end |
linear |
Constant speed |
cubic-bezier() |
Custom curve |
flowchart LR
subgraph Timing["Timing Functions"]
Ease["ease<br>Natural feel"]
Linear["linear<br>Constant speed"]
EIO["ease-in-out<br>Smooth start & end"]
end
style Ease fill:#3b82f6,color:#fff
style Linear fill:#22c55e,color:#fff
style EIO fill:#f59e0b,color:#fff
The transform Property
transform lets you visually transform elements without affecting the document layout.
/* Translate (move) */
transform: translateX(20px);
transform: translateY(-10px);
transform: translate(20px, -10px);
/* Scale */
transform: scale(1.1);
transform: scale(1.5, 0.5);
/* Rotate */
transform: rotate(45deg);
/* Skew */
transform: skew(10deg);
/* Combine multiple transforms */
transform: translate(20px, 0) scale(1.1) rotate(5deg);
| Function | Effect | Example |
|---|---|---|
translate() |
Move | translate(10px, 20px) |
scale() |
Resize | scale(1.2) |
rotate() |
Rotate | rotate(45deg) |
skew() |
Skew | skew(10deg) |
transform-origin
Changes the point around which the transform is applied.
.card {
transform-origin: top left;
transform: rotate(5deg);
}
Common Transition Patterns
Hover Lift Effect
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
Button Effect
.btn {
transition: all 0.2s ease;
}
.btn:hover {
background-color: #1d4ed8;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}
.btn:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3);
}
Fade In
.fade {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.fade.visible {
opacity: 1;
transform: translateY(0);
}
CSS Animations with @keyframes
For animations more complex than a simple A-to-B transition, use @keyframes.
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.element {
animation: fadeIn 0.5s ease forwards;
}
Multiple Keyframes
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 2s ease-in-out infinite;
}
The animation Property
animation-name: fadeIn;
animation-duration: 0.5s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: 1; /* Use 'infinite' for looping */
animation-direction: normal; /* 'alternate' for back-and-forth */
animation-fill-mode: forwards; /* Keeps the final state */
/* Shorthand */
animation: fadeIn 0.5s ease 0s 1 normal forwards;
| Property | Example Values | Description |
|---|---|---|
iteration-count |
infinite, 3 |
How many times to repeat |
direction |
normal, alternate, reverse |
Playback direction |
fill-mode |
forwards, backwards, both |
State before/after animation |
Common Animation Patterns
Spinner
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #e2e8f0;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
Bounce
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
.bounce {
animation: bounce 1s ease infinite;
}
Slide In
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.slide-in {
animation: slideIn 0.5s ease forwards;
}
Performance Considerations
GPU-Accelerated Properties
Not all CSS properties animate equally well. Some trigger expensive layout recalculations, while others are handled efficiently by the GPU.
/* Fast (GPU-composited) */
transform: translateX(100px);
opacity: 0.5;
/* Slow (triggers layout recalculation) */
left: 100px;
width: 200px;
margin-left: 100px;
| Property | Performance |
|---|---|
transform |
Fast |
opacity |
Fast |
color, background-color |
Moderate |
width, height, margin |
Slow |
Rule of thumb: Animate using
transformandopacitywhenever possible. Usetranslate()instead ofleft/topfor moving elements.
will-change
Hints the browser to prepare for an upcoming animation.
.animated-element {
will-change: transform, opacity;
}
Caution: Use
will-changesparingly. It consumes extra memory, so only apply it to elements you know will animate.
Accessibility: prefers-reduced-motion
Some users experience discomfort or disorientation from motion on screen. The prefers-reduced-motion media query lets you respect their preferences.
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Important: Always include
prefers-reduced-motionsupport in any project with animations. This is an accessibility requirement, not an optional nicety.
Practice: Interactive Cards
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, sans-serif;
background: #f8fafc;
padding: 48px 16px;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
max-width: 900px;
margin: 0 auto;
}
.card {
background: white;
border-radius: 12px;
padding: 32px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-8px);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.12);
}
.card h3 {
margin-bottom: 12px;
}
.card p {
color: #64748b;
margin-bottom: 16px;
}
.card .btn {
display: inline-block;
background: #3b82f6;
color: white;
padding: 8px 20px;
border-radius: 6px;
text-decoration: none;
font-weight: 600;
transition: background-color 0.2s ease, transform 0.1s ease;
}
.card .btn:hover {
background: #2563eb;
transform: translateY(-1px);
}
.card .btn:active {
transform: translateY(0);
}
/* Accessibility */
@media (prefers-reduced-motion: reduce) {
.card,
.card .btn {
transition: none;
}
}
Summary
| Concept | Description |
|---|---|
transition |
Smoothly interpolates property changes |
transform |
Visually transforms elements (move, scale, rotate) |
@keyframes |
Defines complex multi-step animations |
animation |
Applies a keyframe animation |
will-change |
Optimization hint for the browser |
prefers-reduced-motion |
Accessibility media query for motion sensitivity |
Key Takeaways
- Use
transformandopacityfor performant animations transitionis for simple state changes;@keyframesis for complex sequences- Always support
prefers-reduced-motion - Choose GPU-composited properties for smooth 60fps motion
Exercises
Exercise 1: Basics
Create a button that changes color and lifts slightly on hover with a smooth transition.
Exercise 2: Intermediate
Build a loading spinner using @keyframes and the animation property.
Challenge
Implement a fade-in-on-scroll animation using @keyframes and JavaScript's IntersectionObserver. Make sure to respect prefers-reduced-motion.
References
Next up: In Day 10, you will tackle the Final Project -- putting every CSS concept from the past 9 days together to style a complete portfolio site!