Home JavaScript CSS Flexbox Complete Guide: Layouts Explained From Scratch

CSS Flexbox Complete Guide: Layouts Explained From Scratch

In Plain English 🔥
Imagine you're packing books onto a shelf. Normally you'd place each book one by one, guessing how much space is left. Flexbox is like a magic shelf that automatically figures out how to space, stretch, and align every book for you — even if the books are different sizes. You just tell the shelf the rules ('keep everything centred', 'spread them out evenly') and it handles the maths. That's exactly what Flexbox does for elements on a webpage.
⚡ Quick Answer
Imagine you're packing books onto a shelf. Normally you'd place each book one by one, guessing how much space is left. Flexbox is like a magic shelf that automatically figures out how to space, stretch, and align every book for you — even if the books are different sizes. You just tell the shelf the rules ('keep everything centred', 'spread them out evenly') and it handles the maths. That's exactly what Flexbox does for elements on a webpage.

Before Flexbox arrived, building even a simple two-column layout in CSS felt like solving a puzzle with missing pieces. Developers leaned on floats, negative margins, and inline-block hacks just to centre a button on screen — and those solutions broke the moment the screen size changed. Flexbox (short for Flexible Box Layout) was introduced specifically to fix this pain point, and it's now the backbone of nearly every modern web layout you see.

The Two Players: Flex Container and Flex Children

Flexbox always involves a relationship between two things: a parent element called the flex container and the direct children inside it called flex items. Think of it like a food tray (the container) holding individual dishes (the items). When you apply display: flex to the tray, it immediately gains superpowers — it can decide how to line up, space out, and resize every dish automatically.

The key rule beginners miss: Flexbox properties split into two groups. Some properties go on the container (like justify-content and align-items) and some go on the items (like flex-grow and align-self). Mixing them up on the wrong element is the number-one source of confusion.

To activate Flexbox you write exactly one CSS rule on the parent: display: flex. That single line transforms the layout behaviour of every direct child underneath it. Children don't need to do anything — they become flex items the moment their parent becomes a flex container.

flexbox-basics.html · CSS
12345678910111213141516171819202122232425262728293031323334353637383940
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>FlexboxContainer vs Items</title>
  <style>

    /* ── THE FLEX CONTAINER ──────────────────────────────── */
    .recipe-card-row {
      display: flex;           /* This single line activates Flexbox */
      background: #f0f4f8;
      padding: 16px;
      gap: 12px;               /* Adds equal breathing space between items */
    }

    /* ── THE FLEX ITEMS (children of .recipe-card-row) ───── */
    .recipe-card {
      background: #ffffff;
      border: 1px solid #d1d9e0;
      border-radius: 8px;
      padding: 20px;
      /* No width needed — Flexbox handles distribution */
    }

  </style>
</head>
<body>

  <!-- The PARENT is the flex container -->
  <div class="recipe-card-row">

    <!-- Each direct child automatically becomes a flex item -->
    <div class="recipe-card">🍕 Pizza</div>
    <div class="recipe-card">🍣 Sushi</div>
    <div class="recipe-card">🥗 Salad</div>

  </div>

</body>
</html>
▶ Output
Three white cards sit side by side on a light-grey background, each with 12px of gap between them. Without writing a single float or inline-block rule, they line up horizontally because display: flex made the parent a flex container.
⚠️
Watch Out:display: flex only affects DIRECT children, not grandchildren. If you nest a div inside a flex item and want THAT to also use Flexbox, you must add display: flex to the inner div separately.

Understanding the Two Axes — Main and Cross

Here's the concept that unlocks everything else in Flexbox: there are always two invisible lines running through your flex container. The main axis is the direction your items flow. The cross axis is perpendicular to it — at a right angle.

By default the main axis runs left to right (horizontal), so items line up in a row. You change this with flex-direction. Set it to column and the main axis flips to top-to-bottom, stacking items vertically like a list.

Why does this matter? Because the alignment properties — justify-content and align-items — are defined relative to these axes, not to specific directions. justify-content always controls the main axis. align-items always controls the cross axis. Once this clicks, you'll never forget which property does what.

Think of a road (main axis) and a pavement beside it (cross axis). justify-content moves cars along the road. align-items moves them sideways onto or off the pavement.

flex-axes-demo.html · CSS
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Flexbox AxesMain vs Cross</title>
  <style>

    .navigation-bar {
      display: flex;
      flex-direction: row;       /* Default: main axis = LEFTRIGHT */
      justify-content: space-between; /* Spread items along the MAIN axis */
      align-items: center;       /* Centre items on the CROSS axis (top↕bottom) */
      background: #1a202c;
      padding: 0 24px;
      height: 60px;
    }

    .nav-logo {
      color: #63b3ed;
      font-weight: bold;
      font-size: 1.2rem;
    }

    .nav-links {
      display: flex;             /* Nested flex container for the link group */
      gap: 20px;
      list-style: none;
      margin: 0;
      padding: 0;
    }

    .nav-links a {
      color: #e2e8f0;
      text-decoration: none;
    }

    /* ── COLUMN DIRECTION EXAMPLE ─────────────────────────── */
    .sidebar-menu {
      display: flex;
      flex-direction: column;    /* Main axis flips: now TOPBOTTOM */
      align-items: flex-start;   /* Items hug the LEFT side of the cross axis */
      gap: 8px;
      background: #2d3748;
      padding: 16px;
      width: 200px;
    }

    .sidebar-menu a {
      color: #e2e8f0;
      text-decoration: none;
      padding: 8px 12px;
      border-radius: 4px;
      width: 100%;
    }

    .sidebar-menu a:hover {
      background: #4a5568;
    }

  </style>
</head>
<body>

  <!-- HORIZONTAL nav (flex-direction: row) -->
  <nav class="navigation-bar">
    <span class="nav-logo">TheCodeForge</span>
    <ul class="nav-links">
      <li><a href="#">Home</a></li>
      <li><a href="#">Articles</a></li>
      <li><a href="#">About</a></li>
    </ul>
  </nav>

  <!-- VERTICAL sidebar (flex-direction: column) -->
  <div class="sidebar-menu">
    <a href="#">Dashboard</a>
    <a href="#">Projects</a>
    <a href="#">Settings</a>
  </div>

</body>
</html>
▶ Output
A dark horizontal navigation bar appears at the top with 'TheCodeForge' on the far left and three links on the far right, perfectly vertically centred. Below it, a dark sidebar shows three links stacked vertically, each taking full width.
⚠️
Memory Trick:justify-content → J → think 'Journey along the main axis'. align-items → A → think 'Across the cross axis'. That association alone will save you from Googling which is which for the rest of your career.

Alignment Deep Dive — justify-content, align-items, and align-self

Now that you know the axes exist, let's master the properties that control them. These three are responsible for roughly 80% of every layout you'll ever build with Flexbox.

justify-content accepts values like flex-start (pack left), flex-end (pack right), center (middle), space-between (first item at start, last at end, even gaps between), and space-around (equal space on both sides of each item). space-between is the most commonly used in real nav bars and card grids.

align-items works on the cross axis: stretch (default — items fill the container height), center, flex-start, and flex-end.

align-self is the escape hatch. It goes on an individual flex item and overrides align-items just for that one child. It's perfect when one card in a row needs to sit at the top while the rest are centred.

The classic 'centre a div on screen' problem — which tortured CSS developers for years — is solved in two lines with Flexbox.

flexbox-alignment.html · CSS
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Flexbox Alignment Examples</title>
  <style>

    * { box-sizing: border-box; margin: 0; padding: 0; }

    body {
      font-family: sans-serif;
      padding: 24px;
      background: #f7fafc;
    }

    /* ── EXAMPLE 1: Classic centred hero section ─────────── */
    .hero-section {
      display: flex;
      justify-content: center;   /* Centre content along main axis (horizontal) */
      align-items: center;       /* Centre content along cross axis (vertical) */
      height: 200px;
      background: #2b6cb0;
      border-radius: 8px;
      margin-bottom: 24px;
    }

    .hero-section h1 {
      color: white;
      font-size: 2rem;
    }

    /* ── EXAMPLE 2: space-between for a dashboard stat row ─ */
    .stats-row {
      display: flex;
      justify-content: space-between; /* Even gaps between stat cards */
      align-items: stretch;           /* All cards match the tallest card's height */
      gap: 16px;
      margin-bottom: 24px;
    }

    .stat-card {
      background: white;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      padding: 20px;
      flex: 1;  /* Each card takes an equal share of available width */
    }

    .stat-card.featured {
      align-self: flex-start; /* THIS card won't stretch — it stays its natural height */
      background: #ebf8ff;
      border-color: #63b3ed;
    }

    .stat-card h2 { font-size: 2rem; color: #2d3748; }
    .stat-card p  { color: #718096; font-size: 0.85rem; }

  </style>
</head>
<body>

  <!-- EXAMPLE 1: Perfect centring in two CSS rules -->
  <div class="hero-section">
    <h1>Welcome to TheCodeForge</h1>
  </div>

  <!-- EXAMPLE 2: Dashboard stats with align-self override -->
  <div class="stats-row">

    <div class="stat-card">
      <h2>1,284</h2>
      <p>Articles Published</p>
      <p>This is a longer description that makes this card taller than others.</p>
    </div>

    <!-- This card uses align-self to opt OUT of stretching -->
    <div class="stat-card featured">
      <h2>98%</h2>
      <p>Reader Satisfaction</p>
    </div>

    <div class="stat-card">
      <h2>42k</h2>
      <p>Monthly Readers</p>
    </div>

  </div>

</body>
</html>
▶ Output
A blue banner with 'Welcome to TheCodeForge' perfectly centred both horizontally and vertically. Below it, three stat cards sit in a row: the first and third stretch to match the tallest card's height, while the 'featured' card (highlighted in light blue) stays only as tall as its own content because of align-self: flex-start.
🔥
Interview Gold:If an interviewer asks 'How do you centre a div both horizontally and vertically?', the Flexbox answer is: display: flex + justify-content: center + align-items: center on the PARENT. This is the most asked CSS interview question and Flexbox makes it embarrassingly simple.

flex-grow, flex-shrink, and flex-basis — Making Items Flexible

This is where 'Flexible' in Flexbox actually earns its name. These three properties control how each individual item behaves when there's extra space or not enough space.

flex-basis sets the starting size of an item before any space is distributed — think of it as the item's 'wish' for how big it wants to be. flex-grow says 'if there's leftover space, I want this share of it'. A value of 1 means 'take a fair share'. A value of 2 means 'take twice as much as items with 1'. flex-shrink works in reverse — when space runs out, how much should this item shrink? The default is 1, meaning all items shrink equally.

The shorthand flex: 1 is the most common thing you'll write in real projects. It expands to flex-grow: 1, flex-shrink: 1, flex-basis: 0%, meaning 'share all available space equally among siblings'.

flex-wrap is also critical here. By default, Flexbox squeezes all items into one line. Set flex-wrap: wrap and items spill onto the next row when they run out of room — essential for responsive card grids.

flex-grow-shrink-wrap.html · CSS
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>flex-grow, flex-shrink, flex-wrap</title>
  <style>

    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: sans-serif; padding: 24px; background: #f7fafc; }

    /* ── EXAMPLE 1: Unequal columns (sidebar + main content) ── */
    .page-layout {
      display: flex;
      gap: 16px;
      margin-bottom: 32px;
      height: 120px;
    }

    .page-sidebar {
      flex: 0 0 220px;   /* flex-grow:0, flex-shrink:0, flex-basis:220px */
                         /* NEVER grow, NEVER shrink — always exactly 220px */
      background: #2d3748;
      color: white;
      padding: 16px;
      border-radius: 8px;
    }

    .page-main-content {
      flex: 1;           /* Shorthand: grow to fill ALL remaining space */
      background: white;
      border: 1px solid #e2e8f0;
      padding: 16px;
      border-radius: 8px;
    }

    /* ── EXAMPLE 2: Responsive card grid with flex-wrap ─────── */
    .article-grid {
      display: flex;
      flex-wrap: wrap;    /* Items wrap to the next row when space runs out */
      gap: 16px;
    }

    .article-card {
      flex: 1 1 280px;   /* Grow and shrink, but never go below 280px wide */
                         /* This creates a naturally responsive grid */
      background: white;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      padding: 20px;
    }

    .article-card h3 { color: #2d3748; margin-bottom: 8px; }
    .article-card p  { color: #718096; font-size: 0.9rem; }

  </style>
</head>
<body>

  <!-- LAYOUT: Fixed sidebar + Fluid main area -->
  <div class="page-layout">
    <aside class="page-sidebar">Sidebar (always 220px)</aside>
    <main class="page-main-content">Main content (takes all remaining space)</main>
  </div>

  <!-- GRID: Cards wrap to new rows on small screens -->
  <div class="article-grid">
    <div class="article-card">
      <h3>Getting Started with CSS</h3>
      <p>Learn the fundamentals of styling web pages from zero.</p>
    </div>
    <div class="article-card">
      <h3>JavaScript Promises Explained</h3>
      <p>Understand async code without losing your mind.</p>
    </div>
    <div class="article-card">
      <h3>React Hooks Deep Dive</h3>
      <p>Master useState, useEffect, and custom hooks.</p>
    </div>
    <div class="article-card">
      <h3>Node.js for Beginners</h3>
      <p>Build your first server-side app step by step.</p>
    </div>
  </div>

</body>
</html>
▶ Output
Top section: A dark 220px-wide sidebar sits fixed to the left; the white main content area expands to fill all remaining width regardless of screen size. Bottom section: Four article cards arranged in a row on wide screens. On narrower screens, cards automatically drop to two per row, then one per row, because flex-wrap: wrap lets them reflow naturally.
⚠️
Pro Tip:The pattern flex: 1 1 280px on cards combined with flex-wrap: wrap gives you a fully responsive grid with ZERO media queries. This is how modern CSS replaces entire Bootstrap grid systems with just a few lines.
Feature / AspectCSS FlexboxCSS Grid
Best used forSingle-axis layouts (row OR column)Two-axis layouts (rows AND columns simultaneously)
Direction controlflex-direction: row | columnRows and columns defined together with grid-template
Item alignmentjustify-content + align-itemsjustify-items + align-items (same concept, grid context)
Content-driven sizingYes — items size to their content naturallyPossible but layout is more structure-driven
Responsive without media queriesYes — flex-wrap + flex-basis handles most casesYes — with repeat(auto-fill, minmax()) pattern
Typical use casesNavbars, button groups, card rows, centringPage layouts, photo galleries, dashboard grids
Browser supportAll modern browsers + IE11 (with prefixes)All modern browsers, IE11 partial support only
Learning curveLower — fewer properties to learn firstHigher — requires understanding both axes at once from the start

🎯 Key Takeaways

  • display: flex goes on the PARENT container — that one rule makes all direct children into flex items automatically.
  • justify-content controls the MAIN axis, align-items controls the CROSS axis — and those axes SWAP when flex-direction changes to column.
  • flex: 1 is the most powerful shorthand you'll write — it means 'grow and shrink equally with siblings', producing fluid layouts without hardcoded widths.
  • flex-wrap: wrap combined with flex: 1 1 [min-width] on children creates a fully responsive card grid with zero media queries — this pattern replaces entire grid frameworks.

⚠ Common Mistakes to Avoid

  • Mistake 1: Putting justify-content on the wrong element — Symptom: nothing moves, items ignore the property completely — Fix: justify-content and align-items always go on the PARENT (the flex container), never on the child items. If you wrote it on a div that doesn't have display: flex, CSS silently ignores it with zero error messages.
  • Mistake 2: Forgetting that flex-direction: column swaps the axes — Symptom: justify-content: center doesn't centre items vertically as expected — Fix: When flex-direction is column, justify-content moves things UP and DOWN (the main axis is now vertical), and align-items moves things LEFT and RIGHT. The properties don't change — the axes flip. Draw the axes on paper before debugging.
  • Mistake 3: Using flex without flex-wrap on card grids — Symptom: On small screens, all cards squish into a single overflowing row instead of wrapping — Fix: Add flex-wrap: wrap to the container and set a minimum width on items with flex: 1 1 250px. Without flex-wrap: wrap the default is nowrap, meaning Flexbox will shrink items indefinitely rather than wrap them to the next row.

Interview Questions on This Topic

  • QWhat's the difference between justify-content and align-items in Flexbox, and what happens to each when you change flex-direction to column?
  • QHow would you build a navigation bar where the logo is on the left and the nav links are on the right, using only Flexbox? Walk me through your approach.
  • QWhat does flex: 1 actually expand to, and why would you use flex: 0 0 200px on a sidebar — what does each value mean and what behaviour does it produce?

Frequently Asked Questions

When should I use Flexbox instead of CSS Grid?

Use Flexbox when your layout flows in one direction — a row of buttons, a navigation bar, or a vertical list of cards. Use CSS Grid when you need to control both rows and columns at the same time, like a full page layout or a photo gallery. In practice, most real projects use both: Grid for the page skeleton, Flexbox inside components.

Why isn't my justify-content: center working?

The most likely cause is that you put justify-content on the flex item instead of the flex container. Check that the element with justify-content also has display: flex on it. The second common cause is that your container has no defined width or height, so there's no extra space to distribute — add a width or height to the container and the alignment will kick in.

What's the difference between align-items and align-content?

align-items aligns flex items within a single row on the cross axis — it works even when everything is on one line. align-content only does anything when you have flex-wrap: wrap enabled AND items have actually wrapped onto multiple rows — it then controls how those rows of items are spaced relative to each other within the container. If your items aren't wrapping, align-content has zero effect.

🔥
TheCodeForge Editorial Team Verified Author

Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.

← PreviousCSS Basics and Box ModelNext →CSS Grid Complete Guide
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged