Skip to main content

Wait, I Only See h-48 for Heightβ€”Where's the Width? Understanding How CSS Grid Automatically Sizes Cards

Β· 14 min read
Mahmut Salman
Software Developer

I built my responsive grid with grid-cols-1 sm:grid-cols-2 md:grid-cols-3, and I see h-48 controlling the image height, but where's the width? πŸ€” There's no w-48 or w-64 on my cards! How do they know how wide to be? My mentor dropped a knowledge bomb: "The grid controls width automaticallyβ€”you don't set it!" This blew my mind. The grid is the boss, and cards just obey. Understanding this changed how I think about responsive layouts! πŸ“βœ¨

The Missing Width Mystery​

Me (Backend Dev): I just built this product grid:

<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
<div className="bg-white rounded-lg shadow-md overflow-hidden">
<div className="h-48 bg-gray-200">
<img src="/product.jpg" className="w-full h-full object-cover" />
</div>
<div className="p-4">
<h3 className="text-lg font-semibold">Product Name</h3>
<p className="text-gray-600">$29.99</p>
</div>
</div>
</div>

I see h-48 controlling the image container height, but where's the width? I don't see any w- classes on the cards! How do they know how wide to be? 🧐

The Grid Width Revelation​

Frontend Mentor: EXCELLENT question! 🎯 You're thinking deeply about layoutβ€”this is advanced understanding!

Let me blow your mind: You DON'T set card width because the GRID does it for you! 🀯

The Grid is the Boss of Width​

<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
↑ ↑ ↑ ↑
These control card width automatically!
</div>

How it works:

  • The grid parent says "I have X columns"
  • The cards (children) automatically divide the available space
  • Each card takes 100% Γ· number_of_columns
  • You never set width manually!

Me: Wait, so the grid just... calculates it for me?

Frontend Mentor: EXACTLY! The grid system is declarative, not manual. You declare "I want 3 columns" and the browser handles all the math! πŸŽ‰

Width Calculation Breakdown​

Frontend Mentor: Let me show you the math at each breakpoint:

πŸ“± Mobile (grid-cols-1)​

<div className="grid grid-cols-1 gap-6">
<div className="card">...</div>
</div>

Visual:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Card 1 (100% width) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Card 2 (100% width) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Card 3 (100% width) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Width calculation:

  • 1 column β†’ Each card takes 100% Γ· 1 = 100% of container width
  • If container is 375px (iPhone), each card is 375px wide
  • Cards stack vertically, each taking full width

πŸ“± Tablet (sm:grid-cols-2)​

<div className="grid sm:grid-cols-2 gap-6">
<div className="card">...</div>
<div className="card">...</div>
</div>

Visual:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Card 1 (50%) β”‚ Card 2 (50%) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Card 3 (50%) β”‚ Card 4 (50%) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Width calculation:

  • 2 columns β†’ Each card takes (100% - gap) Γ· 2 β‰ˆ 50% of container width
  • If container is 768px (iPad), each card is (768px - 24px) Γ· 2 = 372px
  • The gap-6 (24px) is subtracted before division!

πŸ’» Desktop (md:grid-cols-3)​

<div className="grid md:grid-cols-3 gap-6">
<div className="card">...</div>
<div className="card">...</div>
<div className="card">...</div>
</div>

Visual:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Card 1 β”‚ Card 2 β”‚ Card 3 β”‚
β”‚ (~33%) β”‚ (~33%) β”‚ (~33%) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Card 4 β”‚ Card 5 β”‚ Card 6 β”‚
β”‚ (~33%) β”‚ (~33%) β”‚ (~33%) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Width calculation:

  • 3 columns β†’ Each card takes (100% - gaps) Γ· 3 β‰ˆ 33.33% of container width
  • If container is 1024px (laptop), each card is (1024px - 48px) Γ· 3 β‰ˆ 325px
  • Two gaps (between 3 columns) = gap-6 Γ— 2 = 48px

πŸ–₯️ Large Desktop (lg:grid-cols-4)​

<div className="grid lg:grid-cols-4 gap-6">
<div className="card">...</div>
<div className="card">...</div>
<div className="card">...</div>
<div className="card">...</div>
</div>

Visual:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Card 1 β”‚ Card 2 β”‚ Card 3 β”‚ Card 4 β”‚
β”‚ (25%) β”‚ (25%) β”‚ (25%) β”‚ (25%) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Card 5 β”‚ Card 6 β”‚ Card 7 β”‚ Card 8 β”‚
β”‚ (25%) β”‚ (25%) β”‚ (25%) β”‚ (25%) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Width calculation:

  • 4 columns β†’ Each card takes (100% - gaps) Γ· 4 = 25% of container width
  • If container is 1440px (desktop), each card is (1440px - 72px) Γ· 4 = 342px
  • Three gaps (between 4 columns) = gap-6 Γ— 3 = 72px

The Gap Factor: Width Isn't Exactly 50%​

Me: Wait, you said (100% - gap) Γ· 2 for 2 columns. Why subtract the gap?

Frontend Mentor: Sharp eye! πŸ‘€ The gap takes up space too!

Understanding Gap in Width Calculation​

<div className="grid grid-cols-2 gap-6">
<div>Card 1</div>
<div>Card 2</div>
</div>

Total available space breakdown:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ [Card 1] [24px gap] [Card 2] β”‚
β”‚ (?) (?) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Container width: 100%
Gap space: 24px (gap-6)
Remaining for cards: 100% - 24px

Card 1 width: (100% - 24px) Γ· 2
Card 2 width: (100% - 24px) Γ· 2

Real numbers example:

Container: 768px
Gap: 24px
Remaining: 768px - 24px = 744px

Card 1: 744px Γ· 2 = 372px
Card 2: 744px Γ· 2 = 372px

Visual:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ [── 372px ──] [24px] [── 372px ──] β”‚
β”‚ Card 1 gap Card 2 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Total: 372 + 24 + 372 = 768px βœ…

Multiple Gaps with More Columns​

3 columns = 2 gaps:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ [Card] [gap] [Card] [gap] [Card] β”‚
β”‚ ↑ ↑ β”‚
β”‚ gap-6 gap-6 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Total gap space: 24px Γ— 2 = 48px
Card width: (Container width - 48px) Γ· 3

4 columns = 3 gaps:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ [Card] [gap] [Card] [gap] [Card] [gap] [Card] β”‚
β”‚ ↑ ↑ ↑ β”‚
β”‚ gap-6 gap-6 gap-6 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Total gap space: 24px Γ— 3 = 72px
Card width: (Container width - 72px) Γ· 4

Complete Size Control: Who Controls What?​

Me: So grid controls width, but what about height?

Frontend Mentor: Great question! Let me break down the ENTIRE sizing hierarchy:

The Sizing Hierarchy​

<div className="grid grid-cols-3 gap-6">
↑ Grid parent
Controls: Column count (which determines card width)
Does NOT control: Card height

<div className="card bg-white rounded-lg shadow-md overflow-hidden">
↑ Card (grid child)
Width: Automatic from grid (33.33% in this case)
Height: Grows with content (default behavior)

<div className="h-48 bg-gray-200">
↑ Image container
Width: Inherits from card (no explicit width set)
Height: Fixed at h-48 (192px)

<img src="/product.jpg" className="w-full h-full object-cover" />
↑ Image
Width: w-full (100% of image container)
Height: h-full (100% of image container = 192px)
Object-fit: object-cover (crops to fill container)
</div>

<div className="p-4">
↑ Content area
Width: Inherits from card
Height: Grows with content
</div>
</div>
</div>

Size Control Table​

ElementWidth ControlHeight Control
Grid ParentDetermines columnsNo control (flexible)
CardAutomatic from gridGrows with content
Image Containerw-full (inherits card width)h-48 (fixed 192px)
Imagew-full (fills container)h-full (fills container)
Content AreaInherits card widthGrows with content

Key Insight Diagram​

β”Œβ”€ Grid Container (width: 100%) ─────────────────┐
β”‚ β”‚
β”‚ β”Œβ”€ Card (width: 33.33% AUTO) ───────────┐ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€ Image Container (h-48) ─────────┐ β”‚ β”‚
β”‚ β”‚ β”‚ Width: 100% of card β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ Height: 192px FIXED β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ β”Œβ”€ Image (w-full h-full) ─┐ β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ Fills container β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€ Content (p-4) ─────────────────┐ β”‚ β”‚
β”‚ β”‚ β”‚ Title, Price, etc. β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ Height: FLEXIBLE (content) β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Width Flow: Grid β†’ Card (AUTO) β†’ Image Container (inherit) β†’ Image (w-full)
Height Flow: You set h-48 β†’ Image Container β†’ Image (h-full)

Why You DON'T Set Card Width​

Me: What if I DO set a width on the cards? Like w-64?

Frontend Mentor: Let me show you why that breaks the responsive design! πŸ’₯

Breaking the Grid with Fixed Width​

❌ DON'T DO THIS:
<div className="grid grid-cols-3 gap-6">
<div className="w-64 card"> {/* ← Fixed 256px width */}
...
</div>
</div>

What happens:

Desktop (wide enough):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 256px β”‚ 256px β”‚ 256px β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Lots of wasted space β†’ [empty space]

Mobile (narrow):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 256px β”‚ ← Breaks out of container!
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Horizontal scroll appears! 😱

Problems:

  • ❌ Cards don't fill available space on desktop (wasted space)
  • ❌ Cards overflow container on mobile (horizontal scrollbar)
  • ❌ Breaks responsive design completely
  • ❌ Not flexible or adaptive

The Grid Way (Correct)​

βœ… DO THIS:
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
<div className="card"> {/* ← No width set! */}
...
</div>
</div>

What happens:

Desktop:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Flexible β”‚ Flexible β”‚ Flexible β”‚
β”‚ fills 33% β”‚ fills 33% β”‚ fills 33% β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Perfect use of space! ✨

Mobile:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Flexible β”‚
β”‚ fills 100% β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Perfect fit! ✨

Benefits:

  • βœ… Cards automatically fill available space
  • βœ… Responsive at all screen sizes
  • βœ… No overflow or scrollbars
  • βœ… Flexible and adaptive

The w-full Pattern for Images​

Me: But I DO see w-full on the image! Isn't that setting width?

Frontend Mentor: Aha! Great observation! w-full has a special meaning!

Understanding w-full​

<img src="/product.jpg" className="w-full h-full object-cover" />
↑
"Fill my parent container"

What w-full means:

  • width: 100% (in CSS)
  • "Be as wide as my parent element"
  • NOT a fixed width!
  • Relative to parent container

The Flow of w-full​

<div className="grid grid-cols-3">
↑ Grid: "Each column is 33.33% of me"

<div className="card">
↑ Card: "I'm 33.33% of grid" (automatic)

<div className="h-48">
↑ Image container: "I'm 100% of card width" (default)

<img className="w-full h-full" />
↑ Image: "I'm 100% of image container" (w-full)
</div>
</div>
</div>

Width cascade:

Grid container: 1200px
↓
Card: 1200px Γ· 3 = 400px (grid controls this)
↓
Image container: 400px (inherits from card)
↓
Image: 400px (w-full = 100% of 400px)

The key:

  • w-full is relative (adapts to parent)
  • Card width is automatic (grid controls it)
  • Result: Everything scales together! πŸ“

Practical Example: Complete Card Breakdown​

Me: Can you show me a complete card with all the sizing explained?

Frontend Mentor: Absolutely! Here's a production card with full annotations:

Complete Product Card​

<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 p-6">
{/* ↑ Grid parent controls card widths automatically */}

<div className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-shadow">
{/* ↑ Card wrapper - NO WIDTH SET! Grid controls it! */}
{/* Width: Auto (100% in mobile, 50% in tablet, 33% in desktop, 25% in large) */}
{/* Height: Grows with content */}

<div className="relative h-48 bg-gray-200">
{/* ↑ Image container */}
{/* Width: Inherits from card (no explicit width needed) */}
{/* Height: Fixed at 192px (h-48) */}

<img
src="/product.jpg"
alt="Product"
className="w-full h-full object-cover"
/>
{/* ↑ Image */}
{/* Width: w-full = 100% of image container (inherits card width) */}
{/* Height: h-full = 100% of image container = 192px */}
{/* object-cover: Crop to fill container maintaining aspect ratio */}

<div className="absolute top-2 right-2 bg-red-500 text-white px-2 py-1 rounded-md text-sm font-bold">
SALE
</div>
{/* ↑ Badge - width auto-sizes to content */}
</div>

<div className="p-4">
{/* ↑ Content area */}
{/* Width: Inherits from card */}
{/* Height: Grows with content (flexible) */}

<h3 className="text-lg font-semibold mb-2 line-clamp-2">
Wireless Bluetooth Headphones with Noise Cancelling
</h3>
{/* ↑ Title - width fills parent, height grows with text */}

<p className="text-gray-600 text-sm mb-4 line-clamp-3">
High-quality audio with active noise cancellation and 30-hour battery life
</p>
{/* ↑ Description - flexible height with line clamp */}

<div className="flex items-center justify-between">
{/* ↑ Price row - width fills parent, height based on content */}

<div>
<span className="text-2xl font-bold text-blue-600">$79.99</span>
<span className="text-sm text-gray-500 line-through ml-2">$99.99</span>
</div>

<button className="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition-colors">
Add to Cart
</button>
{/* ↑ Button - width auto-sizes to content + padding */}
</div>
</div>
</div>
</div>

Size Flow Visualization​

β”Œβ”€ Grid Container (1200px) ──────────────────────────────────┐
β”‚ β”‚
β”‚ β”Œβ”€ Card 1 (400px AUTO) ────┐ β”Œβ”€ Card 2 (400px AUTO) ──┐ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€ h-48 (192px) ────────┐│ β”‚ β”Œβ”€ h-48 (192px) ──────┐│ β”‚
β”‚ β”‚ β”‚ Width: 400px (inherit)β”‚β”‚ β”‚ β”‚ Width: 400px β”‚β”‚ β”‚
β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β”‚ β”‚β”‚ β”‚
β”‚ β”‚ β”‚ β”Œβ”€ w-full h-full ───┐││ β”‚ β”‚ β”Œβ”€ w-full h-full ─┐││ β”‚
β”‚ β”‚ β”‚ β”‚ img: 400Γ—192px β”‚β”‚β”‚ β”‚ β”‚ β”‚ img: 400Γ—192px β”‚β”‚β”‚ β”‚
β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€ p-4 (Content) ───────┐│ β”‚ β”Œβ”€ p-4 (Content) ────┐│ β”‚
β”‚ β”‚ β”‚ Width: 400px β”‚β”‚ β”‚ β”‚ Width: 400px β”‚β”‚ β”‚
β”‚ β”‚ β”‚ Height: FLEXIBLE β”‚β”‚ β”‚ β”‚ Height: FLEXIBLE β”‚β”‚ β”‚
β”‚ β”‚ β”‚ - Title β”‚β”‚ β”‚ β”‚ - Title β”‚β”‚ β”‚
β”‚ β”‚ β”‚ - Description β”‚β”‚ β”‚ β”‚ - Description β”‚β”‚ β”‚
β”‚ β”‚ β”‚ - Price & Button β”‚β”‚ β”‚ β”‚ - Price & Button β”‚β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Grid: md:grid-cols-3
Card widths: 400px EACH (1200px Γ· 3 = 400px)
Gaps: 24px between cards (gap-6)

Common Sizing Mistakes​

Me: What mistakes should I avoid with grid sizing?

Frontend Mentor: Here are the classics! 🚨

Mistake 1: Setting Fixed Width on Cards​

❌ WRONG:
<div className="grid grid-cols-3 gap-6">
<div className="w-64 card"> {/* Fixed 256px - breaks responsive! */}
...
</div>
</div>

βœ… RIGHT:
<div className="grid grid-cols-3 gap-6">
<div className="card"> {/* No width - grid handles it! */}
...
</div>
</div>

Mistake 2: Using max-w on Grid Children​

❌ WRONG:
<div className="grid grid-cols-3 gap-6">
<div className="max-w-sm card"> {/* Limits width - defeats grid! */}
...
</div>
</div>

βœ… RIGHT:
<div className="grid grid-cols-3 gap-6 max-w-7xl mx-auto">
{/* ↑ Put max-w on grid container! */}
<div className="card">
...
</div>
</div>

Mistake 3: Forgetting h- on Image Container​

❌ WRONG:
<div className="bg-gray-200"> {/* No height! */}
<img src="/product.jpg" className="w-full h-full" />
{/* Image has no height to fill! Invisible or tiny! */}
</div>

βœ… RIGHT:
<div className="h-48 bg-gray-200"> {/* Fixed height! */}
<img src="/product.jpg" className="w-full h-full object-cover" />
{/* Now image fills 192px height! */}
</div>

Mistake 4: Using w-full on Card​

❌ UNNECESSARY (but not harmful):
<div className="grid grid-cols-3 gap-6">
<div className="w-full card"> {/* Redundant! Already 100% of grid column */}
...
</div>
</div>

βœ… CLEANER:
<div className="grid grid-cols-3 gap-6">
<div className="card"> {/* Already fills grid column */}
...
</div>
</div>

Responsive Sizing in Action​

Me: Show me how card sizes change across breakpoints!

Frontend Mentor: Here's the magic! ✨

Real-World Responsive Example​

<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 p-6">
<div className="card">Product Card</div>
</div>

Actual card widths at different screen sizes:

Screen SizeBreakpointContainer WidthColumnsGapsCard Width
iPhone SE375px375px - 48px padding = 327px10327px
iPad Mini768px768px - 48px padding = 720px224px(720-24)/2 = 348px
Laptop1024px1024px - 48px padding = 976px348px(976-48)/3 = 309px
Desktop1440px1440px - 48px padding = 1392px472px(1392-72)/4 = 330px

Visual progression:

πŸ“± Mobile (375px):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Card (327px) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Card (327px) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“± Tablet (768px):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Card (348px) β”‚ Card (348px) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’» Laptop (1024px):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ C(309px)β”‚ C(309px)β”‚ C(309px)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ–₯️ Desktop (1440px):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚C(330px)β”‚C(330px)β”‚C(330px)β”‚C(330px)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key insight: Card widths adapt automatically to fill available space optimally!

Key Takeaways​

Me: Let me summarize what I learned about grid sizing!

Frontend Mentor: Perfect! Here's your complete guide:

The Golden Rules​

  1. Grid controls width, you control height

    • Grid parent: Sets column count β†’ determines card width
    • You: Set h-48 on image containers β†’ controls height
  2. Never set width on grid children

    • ❌ Don't use w-64, w-96, etc. on cards
    • βœ… Let grid calculate optimal width automatically
  3. Use w-full for images, not cards

    • Cards: No width class needed
    • Images: w-full to fill card width
  4. Gaps reduce available space

    • Card width = (Container width - total gaps) Γ· columns
    • More columns = more gaps = slightly smaller cards

Size Control Hierarchy​

β”Œβ”€ Grid Parent ─────────────────────┐
β”‚ Controls: Column count β”‚
β”‚ Result: Card widths automatic β”‚
β”‚ β”‚
β”‚ β”Œβ”€ Card ─────────────────────┐ β”‚
β”‚ β”‚ Width: AUTO from grid β”‚ β”‚
β”‚ β”‚ Height: Grows with content β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€ Image Container ──────┐│ β”‚
β”‚ β”‚ β”‚ Width: Inherits β”‚β”‚ β”‚
β”‚ β”‚ β”‚ Height: YOU SET (h-48) β”‚β”‚ β”‚
β”‚ β”‚ β”‚ β”‚β”‚ β”‚
β”‚ β”‚ β”‚ β”Œβ”€ Image ───────────┐││ β”‚
β”‚ β”‚ β”‚ β”‚ w-full h-full β”‚β”‚β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ Fills container β”‚β”‚β”‚ β”‚
β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quick Reference​

ElementWidthHeight
Grid100% (or max-w-*)Auto (flexible)
CardAUTO (grid sets it)Auto (grows with content)
Image ContainerInherits from cardYOU SET (h-48, h-64, etc.)
Imagew-full (100% of container)h-full (100% of container)

Remember:​

"The grid is the boss of width!"

  • Grid says "I have 3 columns"
  • Cards automatically become 33.33% wide
  • You never manually set card width
  • Everything just works! ✨

Me: This is brilliant! I was looking for w- classes on my cards when the grid was handling it all along! Now I understand why I only see h-48 for heightβ€”that's the only dimension I need to control manually!

Frontend Mentor: Exactly! 🎯 You've just leveled up your grid knowledge! The grid system is smart:

  • Width: Grid calculates it (automatic, responsive, perfect)
  • Height: You set it where needed (h-48 for images, flexible for text)

This is the beauty of CSS Gridβ€”declarative layout that adapts automatically. No manual width calculations, no media query math, just clean, responsive design! πŸš€

Now go build those beautiful product grids with confidence! πŸ’ͺ


Did you have similar "aha moments" with CSS Grid? Share your discoveries in the comments! πŸ“πŸ’¬