Duration: 60 minutes | Difficulty: Advanced | Prerequisites: Lessons 1-7 completed
By the end of this lesson, you will be able to:
Transitions provide smooth changes between CSS property values over a specified duration.
.element {
transition: property duration timing-function delay;
}
/* Examples */
.button {
background: #3498db;
transition: background 0.3s ease;
}
.button:hover {
background: #2980b9;
}
/* Multiple properties */
.card {
transform: scale(1);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: scale(1.05);
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
}
.element {
transition-property: opacity, transform;
transition-duration: 0.3s, 0.5s;
transition-timing-function: ease, ease-in-out;
transition-delay: 0s, 0.1s;
}
/* All properties */
.all-properties {
transition: all 0.3s ease;
}
.linear { transition-timing-function: linear; }
.ease { transition-timing-function: ease; } /* Default */
.ease-in { transition-timing-function: ease-in; }
.ease-out { transition-timing-function: ease-out; }
.ease-in-out { transition-timing-function: ease-in-out; }
/* Custom cubic-bezier */
.custom {
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
/* Steps (for sprite animations) */
.steps {
transition-timing-function: steps(4, end);
}
Animations allow you to animate CSS properties using keyframes, providing more control than transitions.
@keyframes animationName {
0% { /* from */
opacity: 0;
transform: translateY(20px);
}
50% {
opacity: 0.5;
transform: translateY(-10px);
}
100% { /* to */
opacity: 1;
transform: translateY(0);
}
}
/* Alternative syntax */
@keyframes slideIn {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
.animated-element {
animation-name: slideIn;
animation-duration: 0.5s;
animation-timing-function: ease-out;
animation-delay: 0.2s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: both;
animation-play-state: running;
}
/* Shorthand */
.element {
animation: slideIn 0.5s ease-out 0.2s 1 normal both;
}
.normal { animation-direction: normal; } /* Default: forward */
.reverse { animation-direction: reverse; } /* Backward */
.alternate { animation-direction: alternate; } /* Forward, then backward */
.alternate-reverse { animation-direction: alternate-reverse; }
.none { animation-fill-mode: none; } /* Default */
.forwards { animation-fill-mode: forwards; } /* Keep final state */
.backwards { animation-fill-mode: backwards; } /* Apply initial state during delay */
.both { animation-fill-mode: both; } /* Both forwards and backwards */
<div class="button-showcase">
<button class="btn btn-hover">Hover Effect</button>
<button class="btn btn-press">Press Effect</button>
<button class="btn btn-ripple">Ripple Effect</button>
<button class="btn btn-loading">Loading</button>
</div>
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
margin: 0.5rem;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
}
/* Hover effect */
.btn-hover {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
transform: translateY(0);
}
.btn-hover:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
}
.btn-hover:active {
transform: translateY(0);
box-shadow: 0 5px 10px rgba(102, 126, 234, 0.4);
}
/* Press effect */
.btn-press {
background: #e74c3c;
color: white;
transition: transform 0.1s ease;
}
.btn-press:active {
transform: scale(0.95);
}
/* Ripple effect */
.btn-ripple {
background: #2ecc71;
color: white;
}
.btn-ripple::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn-ripple:active::before {
width: 300px;
height: 300px;
}
/* Loading animation */
.btn-loading {
background: #3498db;
color: white;
min-width: 120px;
}
.btn-loading::after {
content: '';
width: 16px;
height: 16px;
border: 2px solid transparent;
border-top: 2px solid white;
border-radius: 50%;
display: inline-block;
margin-left: 8px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
<div class="cards-container">
<div class="card card-fade-in">
<h3>Fade In</h3>
<p>Gentle appearance animation</p>
</div>
<div class="card card-slide-up">
<h3>Slide Up</h3>
<p>Slides up from bottom</p>
</div>
<div class="card card-bounce">
<h3>Bounce</h3>
<p>Playful bounce effect</p>
</div>
</div>
.cards-container {
display: flex;
gap: 2rem;
padding: 2rem;
flex-wrap: wrap;
justify-content: center;
}
.card {
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
width: 250px;
text-align: center;
}
/* Fade in animation */
.card-fade-in {
opacity: 0;
animation: fadeIn 0.8s ease-out forwards;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
/* Slide up animation */
.card-slide-up {
opacity: 0;
transform: translateY(30px);
animation: slideUp 0.6s ease-out 0.2s forwards;
}
@keyframes slideUp {
to {
opacity: 1;
transform: translateY(0);
}
}
/* Bounce animation */
.card-bounce {
animation: bounce 0.8s ease-out 0.4s both;
}
@keyframes bounce {
0%, 20%, 53%, 80%, 100% {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translateY(0);
}
40%, 43% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translateY(-30px);
}
70% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translateY(-15px);
}
90% {
transform: translateY(-4px);
}
}
<div class="loaders">
<div class="loader loader-dots">
<span></span>
<span></span>
<span></span>
</div>
<div class="loader loader-pulse"></div>
<div class="loader loader-bars">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
.loaders {
display: flex;
gap: 4rem;
justify-content: center;
align-items: center;
padding: 4rem;
}
.loader {
display: inline-block;
}
/* Dots loader */
.loader-dots {
display: flex;
gap: 0.5rem;
}
.loader-dots span {
width: 12px;
height: 12px;
border-radius: 50%;
background: #3498db;
animation: dotPulse 1.4s infinite ease-in-out both;
}
.loader-dots span:nth-child(1) { animation-delay: -0.32s; }
.loader-dots span:nth-child(2) { animation-delay: -0.16s; }
@keyframes dotPulse {
0%, 80%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}
/* Pulse loader */
.loader-pulse {
width: 40px;
height: 40px;
background: #e74c3c;
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(0);
opacity: 1;
}
100% {
transform: scale(1);
opacity: 0;
}
}
/* Bars loader */
.loader-bars {
display: flex;
gap: 4px;
align-items: end;
}
.loader-bars div {
width: 6px;
height: 40px;
background: #2ecc71;
animation: bars 1.2s infinite ease-in-out;
}
.loader-bars div:nth-child(1) { animation-delay: -1.2s; }
.loader-bars div:nth-child(2) { animation-delay: -1.1s; }
.loader-bars div:nth-child(3) { animation-delay: -1.0s; }
.loader-bars div:nth-child(4) { animation-delay: -0.9s; }
@keyframes bars {
0%, 40%, 100% {
transform: scaleY(0.4);
}
20% {
transform: scaleY(1);
}
}
/* Page entrance animations */
.page-enter {
animation: pageEnter 0.8s ease-out;
}
@keyframes pageEnter {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Scroll-triggered animations */
.reveal {
opacity: 0;
transform: translateY(50px);
transition: all 0.6s ease-out;
}
.reveal.active {
opacity: 1;
transform: translateY(0);
}
/* Hover animations for interactive elements */
.interactive {
transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.interactive:hover {
transform: scale(1.05) rotate(-2deg);
}
prefers-reduced-motionprefers-reduced-motion/* Good: GPU-accelerated properties */
.good {
transform: translateX(100px);
opacity: 0.5;
}
/* Avoid: Layout-triggering properties */
.avoid {
left: 100px;
width: 200px;
height: 100px;
}
/* Force hardware acceleration */
.accelerated {
will-change: transform;
transform: translateZ(0); /* Create stacking context */
}
animation-fill-mode: forwards do?In Lesson 9, weβll explore Forms & User Interface, learning how to style form controls, create custom inputs, and build beautiful, accessible user interface components.
Animations bring life to your designs. Use them thoughtfully to enhance user experience without overwhelming the interface.