Episode 1 — Fundamentals / 1.8 — CSS Layout Mastery

1.8.d — Combining Grid and Flex

In one sentence: Use Grid for the page-level skeleton (header, sidebar, main, footer) and Flexbox for component-level alignment inside those regions — this combination covers virtually every real-world layout.

Navigation: ← 1.8.c — CSS Grid · 1.8.e — Positioning →


1. The mental model

┌─────────────────────────────────────────┐
│  GRID controls the page skeleton        │
│                                         │
│  ┌─────────────────────────────────┐    │
│  │ FLEX controls component layout  │    │
│  │ (navbar items, card content,    │    │
│  │  button groups, form rows)      │    │
│  └─────────────────────────────────┘    │
│                                         │
└─────────────────────────────────────────┘
LevelToolWhy
Page layout (rows + columns)Grid2D control over header, sidebar, main, footer
Component alignment (single axis)Flexbox1D distribution of items within a region
EitherYour callSome patterns work equally well in both

This is not a hard rule — it is a default starting point that keeps your CSS predictable.


2. Real-world architecture

Header — Flexbox

The header is a single row of items: logo, nav links, actions. Flexbox excels here.

.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  height: 64px;
}

.header nav {
  display: flex;
  gap: 20px;
}

Main content area — Grid

The page body divides into sidebar + content area — a 2D decision.

.page-body {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 24px;
}

Cards within grid — Flexbox

Each card is a vertical stack: image, title, description, action button pushed to the bottom.

.card {
  display: flex;
  flex-direction: column;
}

.card .body {
  flex: 1; /* pushes the action to the bottom */
}

Footer — Flexbox or Grid

Footer columns often use flex with wrapping or grid with auto-fill.

.footer {
  display: flex;
  flex-wrap: wrap;
  gap: 40px;
  justify-content: space-between;
}

3. When to nest grid inside flex

Less common, but useful when a flex item itself needs a 2D layout.

Example: A dashboard widget that lives in a flex row but internally arranges stats in a grid.

.widget-row {
  display: flex;
  gap: 24px;
}

.widget {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr;
  gap: 12px;
}

4. When to nest flex inside grid

The most common nesting pattern. Grid cells contain flex components.

Example: A product listing page.

/* Page-level grid */
.product-page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "filters products"
    "footer  footer";
  min-height: 100vh;
}

/* Product grid (grid inside a grid cell) */
.products {
  grid-area: products;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 20px;
}

/* Each product card uses flex */
.product-card {
  display: flex;
  flex-direction: column;
}

.product-card .price-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: auto; /* pushes to bottom of card */
}

5. Complete page layout example

/* === Page shell: Grid === */
.app {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr auto;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "sidebar footer";
  min-height: 100vh;
}

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

/* === Header: Flex === */
.app-header {
  display: flex;
  align-items: center;
  padding: 0 24px;
  gap: 16px;
}

.app-header .logo { margin-right: auto; }

/* === Sidebar: Flex (vertical) === */
.app-sidebar {
  display: flex;
  flex-direction: column;
  padding: 16px;
  gap: 8px;
}

/* === Main content: Grid for card layout === */
.app-main {
  padding: 24px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
  align-content: start;
}

/* === Cards: Flex (vertical stack) === */
.card {
  display: flex;
  flex-direction: column;
  border-radius: 8px;
  overflow: hidden;
}

.card .content { flex: 1; padding: 16px; }
.card .actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 16px;
}
┌─────────────────────────────────────────────┐
│ [Logo]   Search...            [User] [Menu] │  ← Flex
├────────┬────────────────────────────────────┤
│  Home  │  ┌──────┐ ┌──────┐ ┌──────┐       │
│  Dash  │  │ Card │ │ Card │ │ Card │       │  ← Grid
│  Users │  │(flex)│ │(flex)│ │(flex)│       │     of
│  ···   │  └──────┘ └──────┘ └──────┘       │    Cards
│        │  ┌──────┐ ┌──────┐                │   (flex)
│  ↕     │  │ Card │ │ Card │                │
│ Flex   │  └──────┘ └──────┘                │
├────────┴────────────────────────────────────┤
│                  Footer                     │
└─────────────────────────────────────────────┘
     Grid shell (rows + columns)

6. Decision flowchart

Need to lay things out?
│
├─ One direction (row OR column)?
│  └─ Flexbox
│
├─ Two directions (rows AND columns)?
│  └─ Grid
│
├─ Both? (page skeleton + component details)
│  └─ Grid for the skeleton, Flex for components
│
└─ Positioning an overlay/tooltip/badge?
   └─ position: absolute/fixed (see 1.8.e)

7. Key takeaways

  1. Grid for structure, flex for content is the default starting point.
  2. Nesting flex inside grid cells is the most common real-world pattern.
  3. A complete page typically has 2–3 levels: grid shell → grid/flex regions → flex components.
  4. Neither tool replaces the other — they solve different problems and work best together.

Explain-It Challenge

Explain without notes:

  1. Why is the header typically flex while the page body is grid?
  2. How would you ensure all cards in a grid row have their action buttons aligned at the bottom?
  3. Draw (or describe) the nesting of grid and flex in a typical e-commerce product listing page.

Navigation: ← 1.8.c — CSS Grid · 1.8.e — Positioning →