Master Grid, Transforms, and Animations while building components for your Product Landing Page.
Goal: Build a responsive feature card gallery with grid layout, hover transforms, and entrance animations.
<div class="workspace"> element in the CodePen editor on the right.
What you'll learn:
auto-fit and minmax()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:
<div class="card-grid"> inside the
.workspace element in the CodePen on the right
<article class="card"> elements inside the gridstyle.css, apply CSS Grid to .card-grid:
display: gridgrid-template-columns: repeat(auto-fit, minmax(250px, 1fr))gap: 2remWhy this matters:
auto-fit automatically creates columns based on available spaceminmax(250px, 1fr) means: "Each column is at least 250px, but can grow to fill
space".card {
background: yellow;
min-height: 200px;
border: 1px solid #ddd;
}
Look up grid-template-columns on MDN. What does the fr unit stand
for?
.card-grid exists with
display: grid.card elements inside the
gridrepeat(), auto-fit, and
minmax()Resize your browser window. At what width do cards start stacking? Why is auto-fit
better than hardcoding grid-template-columns: 1fr 1fr 1fr?
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:
<article class="card">:
<div class="card-icon"> with an emoji or decorative element
<h3> with the technique name<p> with a 2-3 sentence descriptionCard 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:
var(--card-bg)π‘ 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!
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:
:root
selector:
:root {
--primary-color: #6366f1;
--secondary-color: #8b5cf6;
--card-bg: #ffffff;
--text-dark: #1f2937;
}
.card styles to use these variables:
background: var(--card-bg);color: var(--text-dark);var(--primary-color) for your card headingsWhy CSS Variables?
<article> element
:root
Look at your card grid. Which card catches your eye first? Why? What makes a good feature card for a product landing page?
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:
.card that scales up slightly:
transform: translateY(-8px) scale(1.02)box-shadow should also grow on hovertransition to make the change smooth:
transition: transform 0.3s ease, box-shadow 0.3s easeWhy 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)Why do we use transform instead of changing width or
top/left? (Hint: Performance)
transform propertytranslateY() and scale() are
appliedHover over your cards. Does the interaction feel smooth? What would happen if you removed the
transition property?
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:
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:
ease-in-out, cubic-bezier())Which card hover effect feels most professional for a product landing page? Which feels too playful? Why?
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:
@keyframesStep 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 endsWhat is the difference between ease, linear, and
ease-in-out?
@keyframes fadeInUp animation exists
animation-delayRefresh 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?
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:
/* 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 */
}
Why is prefers-reduced-motion important for accessibility?
@media (prefers-reduced-motion: no-preference)
Enable reduced motion in your system settings and refresh the page. What happens? Why is this better than just making animations faster or shorter?
Code along as you follow the tutorial β