Ch. 12 — CSS Grid & Animations
Chapter 12 Phase 2 — UX Engineer

CSS Grid & Animations

Flexbox taught you rows and columns. Grid teaches you whole pages. Animations make them feel alive.

⏱ 1 hour 🛠 VS Code · Browser

Flexbox vs Grid — choosing the right tool

You already know Flexbox. It's great for aligning items in a single direction — a row of buttons, a vertical stack, a nav bar. But when you need to place things in two dimensions simultaneously — rows AND columns — that's what CSS Grid is built for.

  • Flexbox — one-dimensional. Items flow in a row or a column. Great for: navbars, button groups, centered content, card headers.
  • CSS Grid — two-dimensional. You define explicit rows and columns. Great for: page layouts, image galleries, dashboards, anything with structure in both axes.
💡 The real answer
Use both — they work great together
A common pattern: use Grid to define the overall page layout (sidebar + main content), then use Flexbox inside each grid cell to arrange the content within it. They're not competing tools.

Grid basics — columns, rows, gaps

css
.grid {
  display: grid;

  /* Define 3 equal columns */
  grid-template-columns: 1fr 1fr 1fr;
  /* Shorthand: repeat(3, 1fr) */

  /* Define rows (usually auto-sized) */
  grid-template-rows: auto;

  /* Gap between cells */
  gap: 24px;
  /* Or: column-gap: 24px; row-gap: 16px; */
}

/* Responsive: as many columns as fit at 280px each */
.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 20px;
}
🔤 Jargon decoded
What is 1fr?
fr stands for "fraction" — a fractional unit of the available space. 1fr 1fr 1fr means three equal columns sharing all available width. 2fr 1fr means the first column gets twice as much space as the second.

Placing items precisely

By default, grid items flow automatically into cells. But you can also tell items exactly where to go — which column to start at, how many columns to span.

css
/* A featured card that spans 2 columns */
.card--featured {
  grid-column: span 2;
}

/* Place precisely: column 1 through 3, row 1 */
.hero {
  grid-column: 1 / 3;
  grid-row: 1;
}

/* Named grid areas — the most readable approach */
.layout {
  display: grid;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "footer  footer";
  grid-template-columns: 280px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

.site-header { grid-area: header; }
.sidebar     { grid-area: sidebar; }
.main-content{ grid-area: main; }
.site-footer { grid-area: footer; }

CSS Transitions — deliberate motion

Transitions animate the change between two CSS states. When a property changes (on hover, on focus, on class toggle), instead of jumping, it smoothly interpolates.

css
.card {
  background: #111;
  transform: translateY(0);
  box-shadow: none;
  /* Animate: property duration easing */
  transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.15s ease;
}

.card:hover {
  background: #161616;
  transform: translateY(-4px);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}

/* Common easing curves */
/* ease       — slow start, fast middle, slow end (default feel) */
/* ease-out   — fast start, slow end (elements arriving) */
/* ease-in    — slow start, fast end (elements leaving) */
/* cubic-bezier(0.34, 1.56, 0.64, 1) — springy overshoot */
💡 Performance tip
Only animate transform and opacity when possible
Animating width, height, margin, or top/left forces the browser to recalculate layout on every frame — expensive. transform and opacity are GPU-accelerated. Use transform: translateY(-4px) instead of margin-top: -4px.

Keyframe animations — full control

Transitions animate between two states. Keyframe animations let you define multiple states at percentage points along a timeline.

css
/* Define the animation */
@keyframes fadeSlideUp {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

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

/* Apply it */
.card {
  /* name duration easing fill-mode */
  animation: fadeSlideUp 0.4s ease-out both;
}

.notification-dot {
  animation: pulse 2s ease-in-out infinite;
}

/* Stagger animations with delay */
.card:nth-child(1) { animation-delay: 0ms; }
.card:nth-child(2) { animation-delay: 80ms; }
.card:nth-child(3) { animation-delay: 160ms; }
🎨
Hands-on activity
Animated product card grid
You need: The in-page IDE below
  1. 1
    The starter code has 4 product cards in a static flex layout. Convert it to CSS Grid with display: grid and grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)).
  2. 2
    Add a hover effect using transition: the card should lift up with transform: translateY(-6px) and get a shadow. Use a smooth easing.
  3. 3
    Bonus: Add a @keyframes fadeSlideUp animation so each card fades in when the page loads. Use animation-delay to stagger them.
Try it right here
Grid layout + hover animations
✦ Own your code
Can you explain every line?
Before moving on: pick any 5 lines from the code above and say out loud what each one does. Not the general idea — the specific line. If Claude ever gives you code like this, hold it to this standard before you use it. If you cannot explain a line, you cannot debug it.
Key takeaways
  • Flexbox for one dimension (rows OR columns); Grid for two dimensions (rows AND columns simultaneously)
  • repeat(auto-fill, minmax(280px, 1fr)) is the magic responsive grid formula — no media queries needed
  • Named grid areas (grid-template-areas) make complex layouts readable and maintainable
  • Only animate transform and opacity — they're GPU-accelerated and won't cause jank
  • Stagger animation delays (animation-delay) to create sequence effects without JavaScript