Flex Container and Flex Items

โ–ถ Try It Yourself

CSS Flexbox โ€” short for Flexible Box Layout โ€” is a one-dimensional layout system that distributes space along a single axis. It solves problems that were nearly impossible with older CSS: centering content vertically, building equal-height columns, and creating navigation bars that spread items automatically. In this lesson you will learn what a flex container is, what flex items are, and the fundamental concept of the main axis vs. the cross axis.

Flex Container vs Flex Items

Concept Description How to Activate
Flex container The parent element that establishes the flex formatting context display: flex or display: inline-flex
Flex items The direct children of the flex container โ€” they automatically become flex participants Automatic when parent has display: flex
Main axis The axis along which flex items are laid out Controlled by flex-direction (default: horizontal)
Cross axis Perpendicular to the main axis Alignment controlled by align-items

flex-direction Values

Value Main Axis Direction Items Flow
row (default) Horizontal left to right In DOM order
row-reverse Horizontal right to left Reversed
column Vertical top to bottom In DOM order
column-reverse Vertical bottom to top Reversed

Essential Alignment Properties

Property Axis Common Values
justify-content Main axis flex-start, flex-end, center, space-between, space-around, space-evenly
align-items Cross axis (all items) stretch (default), flex-start, flex-end, center, baseline
gap Both axes Any length โ€” clean inter-item spacing with no margin hacks
Note: justify-content controls items along the main axis and align-items controls them on the cross axis. These axes swap when you change flex-direction โ€” in a column layout, justify-content: center centers vertically and align-items: center centers horizontally.
Tip: The shortest way to perfectly center any content both horizontally and vertically is: display: flex; align-items: center; justify-content: center; on the parent. This single three-line pattern replaces hacks involving line-height, table-cell, or absolute positioning.
Warning: display: flex only creates a flex context for direct children. Grandchildren remain in normal flow inside their parent flex item. Nesting flex containers inside flex items is perfectly normal and very common in real layouts.

Basic Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Flex Container Basics</title>
  <style>
    *, *::before, *::after { box-sizing: border-box; }
    body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; margin: 0; }

    /* โ”€โ”€ Perfect vertical + horizontal centering โ”€โ”€ */
    .hero {
      display: flex;
      flex-direction: column;   /* main axis = vertical */
      align-items: center;      /* center on cross axis (horizontal) */
      justify-content: center;  /* center on main axis (vertical) */
      min-height: 220px;
      background: linear-gradient(135deg, #4f46e5, #7c3aed);
      border-radius: 16px;
      padding: 32px;
      gap: 16px;
      color: white;
      margin-bottom: 24px;
    }
    .hero h1 { margin: 0; font-size: 1.75rem; text-align: center; }
    .hero p  { margin: 0; opacity: 0.85; text-align: center; max-width: 44ch; line-height: 1.6; }

    /* โ”€โ”€ Horizontal navbar with space-between โ”€โ”€ */
    .navbar {
      display: flex;
      align-items: center;
      justify-content: space-between; /* brand left, links right */
      padding: 12px 24px;
      background: #1e293b;
      border-radius: 10px;
      margin-bottom: 24px;
    }
    .navbar-brand { color: white; font-weight: 700; font-size: 1.1rem; }
    .navbar-links { display: flex; gap: 8px; list-style: none; margin: 0; padding: 0; }
    .navbar-links a {
      color: #94a3b8; text-decoration: none;
      padding: 6px 12px; border-radius: 6px; font-size: 0.875rem;
      transition: color 0.15s, background 0.15s;
    }
    .navbar-links a:hover { color: white; background: #334155; }

    /* โ”€โ”€ Equal-height cards via flex: 1 โ”€โ”€ */
    .card-row { display: flex; gap: 16px; }
    .card {
      flex: 1;                      /* each card takes equal share */
      background: white;
      border: 1px solid #e2e8f0;
      border-radius: 12px;
      padding: 20px;
      display: flex;
      flex-direction: column;       /* stack internals vertically */
    }
    .card h3 { margin: 0 0 8px; font-size: 1rem; color: #0f172a; }
    .card p  { flex: 1; color: #64748b; font-size: 0.875rem; line-height: 1.6; margin: 0 0 16px; }
    .card a  {
      display: inline-block;
      background: #4f46e5; color: white;
      padding: 8px 16px; border-radius: 6px;
      text-decoration: none; font-size: 0.8rem; font-weight: 600;
      align-self: flex-start;   /* button doesn't stretch to full width */
      margin-top: auto;         /* pushes button to card bottom */
    }
  </style>
</head>
<body>

  <div class="hero">
    <h1>Centered with Flexbox</h1>
    <p>flex-direction: column + align-items: center + justify-content: center</p>
  </div>

  <nav class="navbar">
    <span class="navbar-brand">Brand</span>
    <ul class="navbar-links">
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </nav>

  <div class="card-row">
    <div class="card">
      <h3>Card A</h3>
      <p>Short content.</p>
      <a href="#">Learn more</a>
    </div>
    <div class="card">
      <h3>Card B</h3>
      <p>This card has much more content than the others to show that all cards reach the same height automatically thanks to Flexbox.</p>
      <a href="#">Learn more</a>
    </div>
    <div class="card">
      <h3>Card C</h3>
      <p>Medium amount of content here in this card.</p>
      <a href="#">Learn more</a>
    </div>
  </div>

</body>
</html>

How It Works

Step 1 โ€” display: flex Activates the Flex Context

Adding display: flex to a parent instantly makes all its direct children into flex items. They are placed along the main axis (horizontal by default) and stretch to fill the cross axis height by default via align-items: stretch.

Step 2 โ€” flex-direction: column Flips the Axes

In the hero section, flex-direction: column makes the vertical direction the main axis. Now justify-content: center centers vertically and align-items: center centers horizontally โ€” perfect centering with two properties and no absolute positioning.

Step 3 โ€” justify-content: space-between Creates the Navbar Split

With only two children in .navbar, justify-content: space-between places the brand against the left edge and the links against the right edge โ€” all remaining space falls between them. Adding more items distributes space evenly.

Step 4 โ€” flex: 1 Gives Each Card an Equal Share

Each card gets flex: 1 โ€” shorthand for flex-grow: 1; flex-shrink: 1; flex-basis: 0%. All three cards request equal priority for free space, so they always share the row width equally regardless of content length.

Step 5 โ€” margin-top: auto Pins Button to Card Bottom

Inside each card (itself a column flex container), the link gets margin-top: auto. This absorbs all surplus vertical space above the button, pinning it to the card’s bottom โ€” creating perfectly aligned CTAs across all cards regardless of how much text each card contains.

Real-World Example: App Shell Layout

/* app-shell.css */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }

.app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  font-family: system-ui, sans-serif;
}

/* Header โ€” fixed height, never shrinks */
.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  height: 60px;
  background: #1e293b;
  color: white;
  flex-shrink: 0;
}

.header-actions { display: flex; align-items: center; gap: 12px; }

/* Body โ€” flex row (sidebar + main) */
.app-body {
  display: flex;
  flex: 1;
  overflow: hidden;
}

/* Fixed-width sidebar */
.sidebar {
  width: 240px;
  flex-shrink: 0;
  background: #f8fafc;
  border-right: 1px solid #e2e8f0;
  padding: 20px 0;
  overflow-y: auto;
}

/* Main content fills remaining space */
.main-content {
  flex: 1;
  overflow-y: auto;
  padding: 32px;
  background: white;
}

/* Footer โ€” fixed height, never shrinks */
.app-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 24px;
  background: #f1f5f9;
  border-top: 1px solid #e2e8f0;
  font-size: 0.8rem;
  color: #64748b;
  flex-shrink: 0;
}

Common Mistakes

Mistake 1 โ€” Confusing main and cross axis after direction change

โŒ Wrong โ€” expecting justify-content to center horizontally in a column layout:

.column {
  display: flex;
  flex-direction: column;
  justify-content: center; /* centers VERTICALLY โ€” not horizontally */
}

โœ… Correct โ€” use align-items for horizontal centering in a column layout:

.column {
  display: flex;
  flex-direction: column;
  align-items: center;     /* centers horizontally */
  justify-content: center; /* centers vertically */
}

Mistake 2 โ€” Using margin for item spacing instead of gap

โŒ Wrong โ€” margin on flex children creates uneven outer edges:

.flex-row { display: flex; }
.flex-row > * { margin: 0 12px; } /* first and last items have unwanted outer gap */

โœ… Correct โ€” gap applies only between items, never on outer edges:

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

Mistake 3 โ€” flex: 1 causing items to shrink below content width

โŒ Wrong โ€” long text overflows because flex item shrinks below min-content:

.item { flex: 1; } /* can shrink to 0 โ€” text overflows */

โœ… Correct โ€” add min-width: 0 with overflow handling:

.item { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

▶ Try It Yourself

Quick Reference

Property Applies To Common Values
display: flex Container Activates flex layout
flex-direction Container row (default), column, row-reverse, column-reverse
justify-content Container flex-start, center, space-between, space-evenly
align-items Container stretch, center, flex-start, flex-end, baseline
gap Container Any length โ€” replaces margin hacks
flex: 1 Item Grow + shrink equally from 0 basis
align-self Item Override align-items for one item
margin-top: auto Item Absorbs free space โ€” pins item to far edge

🧠 Test Yourself

A flex container has flex-direction: column. Which property centers items horizontally?





โ–ถ Try It Yourself