3.8: Transitions & Animations

Learn how to apply colors using various CSS color formats including hex, RGB, and HSL. Master background properties, images, and create stunning visual effects with linear and radial gradients.

1. CSS Transitions

Transitions create smooth changes between CSS property values.

Basic Transition

/* Before */
.button {
  background: #42b883;
  transition: background 0.3s;
}

/* After (on hover) */
.button:hover {
  background: #35a372;
}
/* Result: Color smoothly transitions over 0.3 seconds */

Transition Properties

.element {
  /* transition: property duration timing-function delay */
  transition: background 0.3s ease-in-out 0s;

  /* Individual properties */
  transition-property: background;
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
  transition-delay: 0s;
}

Multiple Transitions

.button {
  transition:
    background 0.3s ease,
    transform 0.2s ease,
    box-shadow 0.3s ease;
}

.button:hover {
  background: #35a372;
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

Transition All

/* Transition all animatable properties */
.element {
  transition: all 0.3s ease;
}

/* ⚠️ Can impact performance - be specific when possible */

2. Timing Functions

Control the acceleration curve of transitions.

Built-in Timing Functions

.element {
  /* Linear - constant speed */
  transition: all 0.3s linear;

  /* Ease (default) - slow start, fast middle, slow end */
  transition: all 0.3s ease;

  /* Ease-in - slow start */
  transition: all 0.3s ease-in;

  /* Ease-out - slow end */
  transition: all 0.3s ease-out;

  /* Ease-in-out - slow start and end */
  transition: all 0.3s ease-in-out;
}

Cubic Bezier (Custom Curves)

.element {
  /* cubic-bezier(x1, y1, x2, y2) */
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

  /* Material Design standard */
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

  /* Bounce effect */
  transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

Tools: cubic-bezier.com

Steps Function

/* Stepped animation */
.element {
  transition: all 1s steps(4); /* 4 discrete steps */
  transition: all 1s steps(10, start);
  transition: all 1s steps(10, end);
}

/* Typewriter effect */
.typewriter {
  width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: width 2s steps(20);
}

.typewriter.active {
  width: 100%;
}

3. Transform Property

Move, scale, rotate, or skew elements.

2D Transforms

/* Translate (move) */
.element {
  transform: translateX(50px);      /* Move right 50px */
  transform: translateY(-20px);     /* Move up 20px */
  transform: translate(50px, -20px); /* Both X and Y */
}

/* Scale (resize) */
.element {
  transform: scale(1.5);            /* 150% size */
  transform: scaleX(0.5);           /* 50% width */
  transform: scaleY(2);             /* 200% height */
  transform: scale(1.2, 0.8);       /* Width 120%, height 80% */
}

/* Rotate */
.element {
  transform: rotate(45deg);         /* 45 degrees clockwise */
  transform: rotate(-90deg);        /* 90 degrees counter-clockwise */
}

/* Skew */
.element {
  transform: skewX(10deg);          /* Tilt horizontally */
  transform: skewY(5deg);           /* Tilt vertically */
  transform: skew(10deg, 5deg);     /* Both */
}

Multiple Transforms

/* Combine transforms (order matters!) */
.element {
  transform: translateX(100px) rotate(45deg) scale(1.5);
}

/* ⚠️ Later transforms affect earlier ones */

Transform Origin

/* Change the pivot point */
.element {
  transform-origin: center;         /* Default */
  transform-origin: top left;
  transform-origin: 50% 50%;
  transform-origin: 100px 50px;
}

/* Rotate around top-left corner */
.card {
  transform-origin: top left;
  transition: transform 0.3s;
}

.card:hover {
  transform: rotate(5deg);
}

4. CSS Animations

Create multi-step animations using keyframes.

Basic Animation

/* Define keyframes */
@keyframes slide-in {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

/* Apply animation */
.element {
  animation: slide-in 0.5s ease-out;
}

Keyframe Percentages

@keyframes bounce {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-100px);
  }
  100% {
    transform: translateY(0);
  }
}

.element {
  animation: bounce 1s ease-in-out;
}

Animation Properties

.element {
  /* animation: name duration timing-function delay iteration-count direction fill-mode */
  animation: slide-in 1s ease-out 0s 1 normal forwards;

  /* Individual properties */
  animation-name: slide-in;
  animation-duration: 1s;
  animation-timing-function: ease-out;
  animation-delay: 0s;
  animation-iteration-count: 1;        /* or infinite */
  animation-direction: normal;          /* or reverse, alternate, alternate-reverse */
  animation-fill-mode: forwards;        /* or backwards, both, none */
  animation-play-state: running;        /* or paused */
}

Iteration Count

/* Run once */
.element {
  animation: fade-in 1s 1;
}

/* Run 3 times */
.element {
  animation: pulse 0.5s 3;
}

/* Run forever */
.element {
  animation: rotate 2s infinite;
}

Animation Direction

/* Normal - start to end */
.element {
  animation: slide-in 1s normal;
}

/* Reverse - end to start */
.element {
  animation: slide-out 1s reverse;
}

/* Alternate - forward then backward */
.element {
  animation: pulse 1s infinite alternate;
}

/* Alternate-reverse - backward then forward */
.element {
  animation: pulse 1s infinite alternate-reverse;
}

Fill Mode

/* None - returns to original state */
.element {
  animation: fade-in 1s none;
}

/* Forwards - stays at end state */
.element {
  animation: fade-in 1s forwards;
}

/* Backwards - starts at first keyframe */
.element {
  animation: fade-in 1s backwards;
}

/* Both - combines forwards and backwards */
.element {
  animation: fade-in 1s both;
}

5. Common Animation Patterns

Fade In

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.element {
  animation: fade-in 0.5s ease-in;
}

Slide In

@keyframes slide-in-left {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

.element {
  animation: slide-in-left 0.5s ease-out;
}

Bounce

@keyframes bounce {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-30px);
  }
}

.element {
  animation: bounce 0.5s ease-in-out;
}

Pulse

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.1);
  }
}

.button {
  animation: pulse 1s infinite;
}

Shake

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
  20%, 40%, 60%, 80% { transform: translateX(10px); }
}

.error {
  animation: shake 0.5s ease-in-out;
}

Rotate

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.spinner {
  animation: rotate 1s linear infinite;
}

Loading Spinner

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #42b883;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

6. Hover Effects

Button Hover

.button {
  background: #42b883;
  color: white;
  padding: 12px 24px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.button:hover {
  background: #35a372;
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.button:active {
  transform: translateY(0);
  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}

Card Hover

.card {
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.card:hover {
  transform: translateY(-8px);
  box-shadow: 0 12px 24px rgba(0,0,0,0.15);
}

Image Zoom

.image-container {
  overflow: hidden;
}

.image-container img {
  transition: transform 0.3s ease;
}

.image-container:hover img {
  transform: scale(1.1);
}

Underline Animation

.link {
  position: relative;
  text-decoration: none;
  color: #42b883;
}

.link::after {
  content: '';
  position: absolute;
  bottom: -2px;
  left: 0;
  width: 0;
  height: 2px;
  background: #42b883;
  transition: width 0.3s ease;
}

.link:hover::after {
  width: 100%;
}

7. Performance Optimization

GPU-Accelerated Properties

Fast (use these for animations):

  • transform
  • opacity
/* Good - GPU accelerated */
.element {
  transition: transform 0.3s, opacity 0.3s;
}

.element:hover {
  transform: translateX(10px);
  opacity: 0.8;
}

Slow (avoid animating these):

  • width, height
  • top, left, right, bottom
  • margin, padding
/* Bad - causes repaints */
.element {
  transition: width 0.3s;
}

.element:hover {
  width: 300px;
}

/* Good - use transform instead */
.element {
  transition: transform 0.3s;
}

.element:hover {
  transform: scaleX(1.5);
}

Will-Change

Hint to browser to optimize for animation.

/* Use sparingly - only for elements that will animate */
.element {
  will-change: transform, opacity;
}

/* Remove after animation */
.element.animated {
  will-change: transform;
  animation: slide-in 0.5s;
}

.element.animation-complete {
  will-change: auto;
}

Reduce Motion

Respect user preferences for reduced motion.

/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Or disable entirely */
@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

8. Practical Examples

Loading Skeleton

@keyframes loading {
  0% {
    background-position: -200px 0;
  }
  100% {
    background-position: calc(200px + 100%) 0;
  }
}

.skeleton {
  background: linear-gradient(
    90deg,
    #f0f0f0 0px,
    #e0e0e0 40px,
    #f0f0f0 80px
  );
  background-size: 200px 100%;
  animation: loading 1.2s ease-in-out infinite;
}

Progress Bar

@keyframes progress {
  from {
    width: 0%;
  }
  to {
    width: 100%;
  }
}

.progress-bar {
  width: 0%;
  height: 4px;
  background: #42b883;
  animation: progress 2s ease-out forwards;
}

Notification Slide In

@keyframes slide-in-right {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.notification {
  position: fixed;
  top: 20px;
  right: 20px;
  animation: slide-in-right 0.5s ease-out;
}

Flip Card

.card-container {
  perspective: 1000px;
}

.card {
  transition: transform 0.6s;
  transform-style: preserve-3d;
}

.card-container:hover .card {
  transform: rotateY(180deg);
}

.card-front,
.card-back {
  backface-visibility: hidden;
}

.card-back {
  transform: rotateY(180deg);
}

9. Practical Exercises

Exercise 3.8.1: Button Interactions

Create buttons with:

  • Smooth background color change
  • Lift effect on hover
  • Press effect on click
  • Ripple animation

Exercise 3.8.2: Loading Animations

Build 3 loading spinners:

  • Rotating circle
  • Bouncing dots
  • Skeleton screen

Exercise 3.8.3: Card Animations

Create animated cards that:

  • Lift on hover
  • Flip to show back
  • Slide in on page load
  • Stagger animation for grid

Exercise 3.8.4: Navigation Transitions

Build a menu with:

  • Slide-in animation
  • Underline hover effect
  • Active state animation
  • Mobile hamburger toggle

10. Knowledge Check

Question 1: What's the difference between transition and animation?

Show answer Transition animates between two states (requires trigger like :hover). Animation can run automatically with multiple keyframes.

Question 2: Which properties are GPU-accelerated?

Show answer transform and opacity are GPU-accelerated and perform best for animations.

Question 3: What does animation-fill-mode: forwards do?

Show answer Keeps the element at the final keyframe state after animation completes.

Question 4: How do you create an infinite animation?

Show answer animation-iteration-count: infinite; or animation: name duration infinite;

Question 5: Why use transform instead of left/top?

Show answer transform is GPU-accelerated and performs better. left/top cause layout recalculation and repaint.

Question 6: How do you respect reduced motion preferences?

Show answer Use @media (prefers-reduced-motion: reduce) to disable or minimize animations for users who prefer reduced motion.

11. Common Mistakes to Avoid

❌ Animating Expensive Properties

/* Bad */
.element {
  transition: width 0.3s;
}

/* Good */
.element {
  transition: transform 0.3s;
}

❌ Forgetting Transform Origin

/* Rotates from center (might look odd) */
.element {
  transform: rotate(45deg);
}

/* Rotates from top-left corner */
.element {
  transform-origin: top left;
  transform: rotate(45deg);
}

❌ Too Many Simultaneous Animations

/* Bad - performance issues */
.element {
  animation: rotate 1s infinite,
             pulse 1s infinite,
             bounce 1s infinite,
             shake 1s infinite;
}

12. Key Takeaways

Transitions - Smooth changes between states ✅ Animations - Multi-step keyframe animations ✅ Transform - GPU-accelerated movement, scaling, rotation ✅ Timing functions - Control animation curves ✅ Performance - Use transform and opacity ✅ Fill mode - Control animation end state ✅ Iteration count - Run once, multiple, or infinite ✅ Accessibility - Respect prefers-reduced-motion ✅ Will-change - Optimize for animation (use sparingly) ✅ Transform origin - Control rotation/scale pivot point


13. Further Resources

Documentation:

Tools:

Inspiration:


Next Steps

Fantastic! You can now create engaging animations and smooth interactions.

In Lesson 3.9: CSS Best Practices, you'll learn to write maintainable, scalable, and professional CSS.