CSS Feature Gallery

Master Grid, Transforms, and Animations while building components for your Product Landing Page.

0% Complete

What You'll Build

Goal: Build a responsive feature card gallery with grid layout, hover transforms, and entrance animations.

πŸ‘‹ Note on "Workspace": When we say "inside the workspace," we mean inside the <div class="workspace"> element in the CodePen editor on the right.

What you'll learn:

  • Creating responsive grid layouts with auto-fit and minmax()
  • Applying transforms for interactive hover states
  • Combining multiple transforms effectively
  • Creating keyframe animations with staggered timing
  • Respecting user motion preferences for accessibility

Part A β€” Grid Foundation

A1) Create the Grid Container

Goal: Create a responsive card grid that automatically adapts from 1 column on mobile to 3 columns on desktop.

You're building a gallery of CSS techniques where each card will showcase a different concept. Before we add content, let's master the grid layout that holds everything together.

Your task:

  1. Create a container <div class="card-grid"> inside the .workspace element in the CodePen on the right
  2. Add 6 empty <article class="card"> elements inside the grid
  3. In style.css, apply CSS Grid to .card-grid:
    • display: grid
    • grid-template-columns: repeat(auto-fit, minmax(250px, 1fr))
    • gap: 2rem

Why this matters:

  • auto-fit automatically creates columns based on available space
  • minmax(250px, 1fr) means: "Each column is at least 250px, but can grow to fill space"
  • Cards will wrap to new rows when the viewport shrinks
πŸ’‘ Temporary styling: Add this to your CSS so you can see the cards while you work:
.card {
  background: yellow;
  min-height: 200px;
  border: 1px solid #ddd;
}
πŸ“š Research checkpoint:

Look up grid-template-columns on MDN. What does the fr unit stand for?

βœ… Checkpoint A

  • .card-grid exists with display: grid
  • At least 6 .card elements inside the grid
  • Grid uses repeat(), auto-fit, and minmax()
  • Cards automatically wrap on narrow screens

πŸ€” Reflect (2–3 sentences):

Resize your browser window. At what width do cards start stacking? Why is auto-fit better than hardcoding grid-template-columns: 1fr 1fr 1fr?

Part B β€” Card Structure & Content

B1) Build Semantic Cards

Goal: Build semantic, well-structured card components with content.

Now that your grid works, let's fill it with actual content. Each card will showcase a CSS techniqueβ€”perfect for your landing page features section.

Your task:

  1. Add content to each <article class="card">:
    • A <div class="card-icon"> with an emoji or decorative element
    • An <h3> with the technique name
    • A <p> with a 2-3 sentence description
  2. Create 6 cards with these topics:
    • Grid Layout β€” "Organize content in flexible columns that adapt to any screen."
    • Flexbox β€” "Align items perfectly within containers for navigation and layouts."
    • Transforms β€” "Add depth and dimension with scale, rotate, and translate."
    • Animations β€” "Bring your page to life with smooth, purposeful motion."
    • CSS Variables β€” "Create reusable design tokens for consistent theming."
    • Video Backgrounds β€” "Add dynamic visual interest with embedded video elements."

Card structure example:

<article class="card">
  <div class="card-icon">🎯</div>
  <h3>Grid Layout</h3>
  <p>Organize content in flexible columns that adapt to any screen size.</p>
</article>

3. Good news β€” the CSS is already written for you!

We've pre-written the card styles so you can focus on learning Grid and Animations. The CSS includes:

  • Clean white background using var(--card-bg)
  • Padding, border-radius, and box-shadow
  • Centered text and proper spacing
  • Styled icons, headings, and paragraphs

πŸ’‘ Want to customize? Feel free to change the colors in the :root variables or adjust any of the card styles to match your personal aesthetic!

B2) Use CSS Variables for Theming

Goal: Learn to use CSS custom properties (variables) for consistent, maintainable styling.

CSS Variables let you define reusable values once and reference them throughout your stylesheet. This makes it easy to create themes and update colors site-wide.

Your task:

  1. At the top of your CSS, define variables in the :root selector:
    :root {
      --primary-color: #6366f1;
      --secondary-color: #8b5cf6;
      --card-bg: #ffffff;
      --text-dark: #1f2937;
    }
  2. Update your .card styles to use these variables:
    • background: var(--card-bg);
    • color: var(--text-dark);
  3. Use var(--primary-color) for your card headings
  4. Bonus: Try changing one variable value and watch all cards update!

Why CSS Variables?

  • Change your entire color scheme by editing 4 lines
  • Create dark mode by overriding variables in a media query
  • More maintainable than find-and-replace

βœ… Checkpoint B

  • Each card has icon, heading, and description
  • Cards use <article> element
  • Cards have padding, border-radius, and box-shadow
  • CSS variables defined in :root
  • Variables used for at least 2 properties

πŸ€” Reflect (2–3 sentences):

Look at your card grid. Which card catches your eye first? Why? What makes a good feature card for a product landing page?

Part C β€” Transform Basics

C1) Add Smooth Hover Effects

Goal: Add smooth hover effects using CSS transforms.

Static cards are fine, but interactive cards feel premium. Transforms let you scale, move, and rotate elements without affecting layout flow.

Your task:

  1. Add a hover state to .card that scales up slightly:
    • transform: translateY(-8px) scale(1.02)
    • box-shadow should also grow on hover
  2. Add a transition to make the change smooth:
    • transition: transform 0.3s ease, box-shadow 0.3s ease

Why these transforms:

  • translateY(-8px) β€” Lifts the card up (feels like it's floating toward you)
  • scale(1.02) β€” Grows the card by 2% (subtle but noticeable)
  • Combined: Creates a "lift and grow" effect
πŸ“š Research checkpoint:

Why do we use transform instead of changing width or top/left? (Hint: Performance)

βœ… Checkpoint C

  • Cards have smooth hover transition
  • Hover state uses transform property
  • Both translateY() and scale() are applied
  • Box shadow changes on hover

πŸ€” Reflect (2–3 sentences):

Hover over your cards. Does the interaction feel smooth? What would happen if you removed the transition property?

Part D β€” Transform Experimentation

D1) Unique Hover Effects

Goal: Explore different transform combinations and make each card unique.

Right now all cards have the same hover effect. Let's add variety by giving specific cards unique transforms.

Your task:

  1. Keep the basic hover on all cards
  2. Add unique hover effects to the card icon using nth-child()

Example variations:

/* Card 1: Icon rotates */
.card:nth-child(1):hover .card-icon {
  transform: rotate(360deg);
  transition: transform 0.6s ease;
}

/* Card 2: Icon scales */
.card:nth-child(2):hover .card-icon {
  transform: scale(1.3);
  transition: transform 0.3s ease;
}

Experiment with:

  • Different rotation angles (180deg, -15deg)
  • Scale values (0.9 for shrink, 1.4 for big grow)
  • Multiple transforms combined
  • Different timing functions (ease-in-out, cubic-bezier())

βœ… Checkpoint D

  • At least 4 cards have unique icon hover effects
  • Different transform types are used (rotate, scale, translate)
  • Some cards combine multiple transforms
  • All transitions feel smooth

πŸ€” Reflect (2–3 sentences):

Which card hover effect feels most professional for a product landing page? Which feels too playful? Why?

Part E β€” Keyframe Animations

E1) Create Entrance Animations

Goal: Create entrance animations using @keyframes so cards fade and slide in when the page loads.

Transforms are instant reactions to hover. Animations run automatically over time. Let's make your cards appear with style.

Your task:

  1. Create a fade-in-up animation using @keyframes
  2. Apply it to all cards with staggered delays
  3. Set initial state so cards are invisible until animation runs

Step 1: Define the animation

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

Step 2: Apply to cards

.card {
  /* existing styles */
  animation: fadeInUp 0.6s ease forwards;
  opacity: 0; /* Start invisible */
}

Step 3: Stagger the delays

.card:nth-child(1) { animation-delay: 0s; }
.card:nth-child(2) { animation-delay: 0.1s; }
.card:nth-child(3) { animation-delay: 0.2s; }
/* ...and so on */

Why this works:

  • forwards keeps the final state (opacity: 1) after animation ends
  • Staggered delays create a "wave" effect
  • Cards appear in sequence, not all at once
πŸ“š Research checkpoint:

What is the difference between ease, linear, and ease-in-out?

βœ… Checkpoint E

  • @keyframes fadeInUp animation exists
  • Cards fade in from invisible to visible
  • Cards slide up while fading in
  • Each card has a different animation-delay
  • Final state persists (cards stay visible)

πŸ€” Reflect (2–3 sentences):

Refresh the page and watch your cards animate in. Does the timing feel right? Too slow? Too fast? What would you change for a real product page?

Part F (Optional) β€” Animation Polish & Accessibility

F1) Respect Reduced Motion

Goal: Respect user preferences and add finishing touches to your animations.

Not everyone wants animations. Users can set a system preference for reduced motionβ€”we should respect it.

Your task:

  1. Wrap your animations in a media query that checks for motion preference
  2. Add a subtle pulse animation to one card to draw attention (optional)
/* Default: no animation */
.card {
  opacity: 1;
  /* existing styles */
}

/* Only animate if motion is okay */
@media (prefers-reduced-motion: no-preference) {
  .card {
    animation: fadeInUp 0.6s ease forwards;
    opacity: 0;
  }
  
  /* Add delays here too */
}
πŸ“š Research checkpoint:

Why is prefers-reduced-motion important for accessibility?

βœ… Checkpoint F

  • Animations wrapped in @media (prefers-reduced-motion: no-preference)
  • Cards still visible without animation
  • Tested with reduced motion enabled

πŸ€” Reflect (2–3 sentences):

Enable reduced motion in your system settings and refresh the page. What happens? Why is this better than just making animations faster or shorter?

πŸ“€ Submission

What to submit

  1. Click "Copy All Reflections" below.
  2. Paste the reflections into your CodePen (HTML tab).
  3. Fork the Pen to save your work.
  4. Submit your Pen URL to Canvas.

Your Workspace

Code along as you follow the tutorial β†’