Chapter 15 Intermediate 45 min min read Updated 2026-04-11

Flexbox - The Complete Guide

Practice Questions →

In This Chapter

What Is It?

What Is Flexbox?

Flexbox (Flexible Box Layout) is a CSS layout system designed to arrange items in a single row or column. With one line -- display: flex -- a container's direct children become flex items that you can align, distribute, wrap, and order with a handful of intuitive properties.

Before flexbox, centering a div was a running joke. With flexbox, it is two lines. Navbars, card grids, pricing tables, form layouts, sidebar + content layouts -- all become dramatically simpler. Flexbox is arguably the single most important CSS feature of the last 15 years.

.container {
  display: flex;
  justify-content: center;  /* horizontal centering */
  align-items: center;      /* vertical centering */
}
/* Any children are now perfectly centered. Done. */

Why Does It Matter?

Why Is Flexbox So Important?

1. It Solves Layout Problems That Used to Be Painful

Centering a div was hard. Equal-height columns were hard. Spacing items evenly was hard. Building a responsive navbar was hard. Flexbox makes all of these trivial. A few properties replace hundreds of lines of float hacks and table tricks.

2. Every Modern Website Uses It

Open any modern website in DevTools. You will see display: flex everywhere -- navbars, buttons, form groups, card layouts, section headers. Flexbox is the default layout tool for one-dimensional arrangements.

3. It Is Responsive by Default

Flex items automatically adjust to available space. Add flex-wrap: wrap and they flow onto new rows when the container gets narrow. Combined with flex: 1, you get responsive layouts with almost no effort.

4. It Makes CSS Fun Again

Once you understand flexbox, layout becomes intuitive. You stop fighting CSS and start actually designing. This is the chapter where CSS clicks for most learners.

Detailed Explanation

Detailed Explanation

1. Flex Container vs Flex Items

Apply display: flex to a PARENT element. The parent becomes a flex container. Its DIRECT children become flex items. Flexbox properties are split into two groups:

  • Container properties: flex-direction, justify-content, align-items, flex-wrap, gap, align-content
  • Item properties: flex-grow, flex-shrink, flex-basis, flex, order, align-self

2. Main Axis vs Cross Axis

This is the most important concept. Flexbox has two axes:

  • Main axis: the direction items are laid out in (horizontal by default)
  • Cross axis: perpendicular to the main axis (vertical by default)

When you change flex-direction, the axes rotate. In a row, the main axis is horizontal. In a column, the main axis is vertical. This matters because justify-content aligns along the MAIN axis and align-items aligns along the CROSS axis.

3. flex-direction

.container {
  display: flex;
  flex-direction: row;            /* default: left to right */
  flex-direction: row-reverse;    /* right to left */
  flex-direction: column;         /* top to bottom */
  flex-direction: column-reverse; /* bottom to top */
}

4. justify-content (MAIN AXIS)

Distributes items along the main axis.

justify-content: flex-start;    /* default: packed at start */
justify-content: flex-end;      /* packed at end */
justify-content: center;        /* centered */
justify-content: space-between; /* first at start, last at end, equal space between */
justify-content: space-around;  /* equal space around each item */
justify-content: space-evenly;  /* equal space between AND at edges */

Memorize space-between for navbars (logo left, links right) and center for everything else.

5. align-items (CROSS AXIS)

Aligns items perpendicular to the main axis.

align-items: stretch;     /* default: fill cross axis */
align-items: flex-start;  /* top (in a row) */
align-items: flex-end;    /* bottom (in a row) */
align-items: center;      /* vertically centered (in a row) */
align-items: baseline;    /* aligned to text baselines */

6. The Holy Grail: Centering

.center {
  display: flex;
  justify-content: center;
  align-items: center;
  /* Anything inside is perfectly centered -- horizontally AND vertically */
}

This one pattern solves the historical 'center a div' problem. Remember it.

7. flex-wrap

By default, flex items try to fit on a single line, even if they have to shrink. flex-wrap lets them wrap onto multiple lines.

flex-wrap: nowrap;   /* default: all on one line */
flex-wrap: wrap;     /* wrap to new lines when needed */
flex-wrap: wrap-reverse;

8. gap

The modern replacement for margin between items. gap works inside flex and grid containers and is much simpler than setting margins.

.container {
  display: flex;
  gap: 16px;          /* space between items */
  gap: 16px 24px;     /* row-gap | column-gap */
}

Use gap. Stop using margins on flex items. Trust me.

9. align-content

Only applies when flex-wrap causes multiple lines. Controls how those LINES are distributed along the cross axis.

align-content: flex-start;
align-content: center;
align-content: space-between;
align-content: space-around;

10. Flex Item Properties

flex-grow

How much an item grows to fill extra space. Default is 0 (do not grow). Values are ratios: flex-grow: 2 grows twice as fast as flex-grow: 1.

.main    { flex-grow: 1; }  /* takes any extra space */
.sidebar { flex-grow: 0; }  /* keeps its natural size */

flex-shrink

How much an item shrinks when there is not enough space. Default is 1 (can shrink). Set to 0 to prevent shrinking.

.logo { flex-shrink: 0; }  /* never shrinks */

flex-basis

The initial size of the item before grow/shrink is applied.

.item { flex-basis: 200px; }  /* starts at 200px, then grows or shrinks */

flex Shorthand

Sets grow, shrink, and basis in one line. The common values you will actually use:

flex: 1;        /* = flex: 1 1 0 -- grow to fill, shrink if needed, start at 0 */
flex: 0 0 auto; /* no grow, no shrink, use content size */
flex: 1 0 200px; /* grow, no shrink, start at 200px */
flex: none;     /* no grow, no shrink, use content size */

Most of the time you just use flex: 1 on items that should fill available space.

order

Reorder items visually without changing the HTML.

.first { order: 1; }
.second { order: 2; }
.hero { order: -1; } /* shows first regardless of source order */

align-self

Override align-items for a single flex item.

.special { align-self: flex-end; }  /* aligned to bottom while others center */

11. Common Flexbox Patterns

Centering everything

display: flex;
justify-content: center;
align-items: center;

Navbar (logo left, links right)

display: flex;
justify-content: space-between;
align-items: center;

Equal-width card grid

.grid { display: flex; gap: 20px; }
.card { flex: 1; }

Sticky footer

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
main { flex: 1; }

Code Examples

Perfect Centering (The Holy Grail)
<!DOCTYPE html>
<html>
<head>
  <style>
    body { margin: 0; font-family: Arial, sans-serif; }
    .hero {
      height: 100vh;
      background: linear-gradient(135deg, #a855f7, #06b6d4);
      display: flex;
      justify-content: center;
      align-items: center;
      color: white;
      text-align: center;
      padding: 20px;
      box-sizing: border-box;
    }
    h1 { font-size: 56px; margin: 0 0 12px; }
    p { font-size: 20px; opacity: 0.9; }
  </style>
</head>
<body>
  <div class="hero">
    <div>
      <h1>Hi, I'm Aarav</h1>
      <p>Perfectly centered horizontally and vertically with flexbox.</p>
    </div>
  </div>
</body>
</html>
Three lines of flexbox replace the decade-long struggle of centering an element. display: flex makes the container a flex container. justify-content: center centers along the main axis (horizontal). align-items: center centers along the cross axis (vertical).
A full-screen gradient hero with a heading and tagline perfectly centered both horizontally and vertically.
Responsive Navbar
<!DOCTYPE html>
<html>
<head>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: Arial, sans-serif; background: #f9fafb; }
    .nav {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 16px 30px;
      background: white;
      box-shadow: 0 2px 10px rgba(0,0,0,0.05);
    }
    .logo { font-weight: bold; color: #a855f7; font-size: 22px; }
    .links {
      display: flex;
      gap: 24px;
      list-style: none;
    }
    .links a {
      color: #4b5563;
      text-decoration: none;
      font-weight: 500;
    }
    .links a:hover { color: #a855f7; }
    .cta {
      padding: 10px 20px;
      background: #a855f7;
      color: white;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-weight: 600;
    }
    main { padding: 40px; }
  </style>
</head>
<body>
  <nav class="nav">
    <div class="logo">Priya.dev</div>
    <ul class="links">
      <li><a href="#">Home</a></li>
      <li><a href="#">Blog</a></li>
      <li><a href="#">Projects</a></li>
      <li><a href="#">About</a></li>
    </ul>
    <button class="cta">Sign Up</button>
  </nav>
  <main>
    <h1>Welcome, friend!</h1>
    <p>This page has a flexbox navbar: logo left, links center, button right.</p>
  </main>
</body>
</html>
The nav uses justify-content: space-between to push the logo left, button right, with the links in between. The links themselves are a nested flex container with gap: 24px for even horizontal spacing. This is the standard navbar pattern.
A modern navbar with a purple logo on the left, navigation links in the middle, and a purple sign-up button on the right.
Equal-Width Card Grid
<!DOCTYPE html>
<html>
<head>
  <style>
    * { box-sizing: border-box; }
    body { font-family: Arial, sans-serif; padding: 40px; background: #f3f4f6; margin: 0; }
    h1 { text-align: center; color: #1a1a2e; margin-bottom: 30px; }
    .grid {
      display: flex;
      gap: 20px;
      flex-wrap: wrap;
      max-width: 1200px;
      margin: 0 auto;
    }
    .card {
      flex: 1 1 240px;
      background: white;
      padding: 24px;
      border-radius: 14px;
      box-shadow: 0 6px 20px rgba(0,0,0,0.06);
    }
    .card h3 { margin: 0 0 8px; color: #a855f7; }
    .card p  { margin: 0; color: #4b5563; line-height: 1.5; font-size: 14px; }
    .icon {
      width: 48px; height: 48px;
      border-radius: 12px;
      background: linear-gradient(135deg, #a855f7, #06b6d4);
      margin-bottom: 12px;
    }
  </style>
</head>
<body>
  <h1>Why Learn with Us</h1>
  <div class="grid">
    <div class="card"><div class="icon"></div><h3>Live Mentors</h3><p>Real teachers, weekly classes, and doubt sessions.</p></div>
    <div class="card"><div class="icon"></div><h3>Projects</h3><p>Build real apps you can show off on your portfolio.</p></div>
    <div class="card"><div class="icon"></div><h3>Flexible</h3><p>Learn at your own pace with recorded backup classes.</p></div>
    <div class="card"><div class="icon"></div><h3>Community</h3><p>Meet other kids who love coding. By Kavya.</p></div>
  </div>
</body>
</html>
flex: 1 1 240px means each card grows (1), shrinks (1), and has a base width of 240px. With flex-wrap: wrap, cards reflow onto new rows when the container gets narrower. Resize the window to see the responsive behavior.
A responsive grid of 4 feature cards that flex to equal widths on wide screens and wrap to multiple rows on narrow screens.
Pricing Cards Layout
<!DOCTYPE html>
<html>
<head>
  <style>
    * { box-sizing: border-box; }
    body { font-family: Arial, sans-serif; padding: 40px 20px; background: #f3f4f6; margin: 0; }
    h1 { text-align: center; color: #1a1a2e; margin-bottom: 30px; }
    .prices {
      display: flex;
      gap: 20px;
      justify-content: center;
      flex-wrap: wrap;
      max-width: 1000px;
      margin: 0 auto;
    }
    .plan {
      flex: 1 1 260px;
      max-width: 300px;
      background: white;
      padding: 32px 24px;
      border-radius: 16px;
      box-shadow: 0 10px 30px rgba(0,0,0,0.08);
      text-align: center;
      display: flex;
      flex-direction: column;
    }
    .plan h3 { margin: 0 0 8px; color: #6b7280; font-size: 14px; text-transform: uppercase; letter-spacing: 0.1em; }
    .price { font-size: 44px; font-weight: 800; color: #1a1a2e; margin: 8px 0; }
    .price small { font-size: 16px; color: #6b7280; font-weight: normal; }
    .features { list-style: none; padding: 0; text-align: left; margin: 20px 0; flex: 1; }
    .features li { padding: 8px 0; border-bottom: 1px solid #f3f4f6; color: #4b5563; font-size: 14px; }
    .btn { padding: 14px; background: #1a1a2e; color: white; border: none; border-radius: 10px; font-weight: 600; cursor: pointer; font-size: 14px; margin-top: auto; }
    .popular { border: 3px solid #a855f7; position: relative; transform: scale(1.05); }
    .popular .btn { background: #a855f7; }
    .tag { position: absolute; top: -14px; left: 50%; transform: translateX(-50%); background: #a855f7; color: white; padding: 4px 16px; border-radius: 999px; font-size: 11px; font-weight: bold; letter-spacing: 0.1em; }
  </style>
</head>
<body>
  <h1>Pick Your Plan</h1>
  <div class="prices">
    <div class="plan">
      <h3>Starter</h3>
      <div class="price">Rs 499 <small>/mo</small></div>
      <ul class="features">
        <li>5 courses</li>
        <li>Community access</li>
        <li>Monthly check-in</li>
      </ul>
      <button class="btn">Get Started</button>
    </div>
    <div class="plan popular">
      <span class="tag">POPULAR</span>
      <h3>Pro</h3>
      <div class="price">Rs 1,299 <small>/mo</small></div>
      <ul class="features">
        <li>All 30 courses</li>
        <li>Weekly live classes</li>
        <li>Project reviews</li>
        <li>1-on-1 mentor</li>
      </ul>
      <button class="btn">Start Pro</button>
    </div>
    <div class="plan">
      <h3>School</h3>
      <div class="price">Rs 4,999 <small>/mo</small></div>
      <ul class="features">
        <li>Up to 30 students</li>
        <li>Teacher dashboard</li>
        <li>Bulk certificates</li>
      </ul>
      <button class="btn">Contact Us</button>
    </div>
  </div>
</body>
</html>
The outer container uses display: flex with gap and wrap. Each plan is also a flex container with flex-direction: column so the button can be pushed to the bottom using margin-top: auto. This ensures buttons line up even if feature lists have different lengths.
Three pricing cards side by side. The middle one is highlighted and slightly larger. All buttons align to the bottom regardless of feature list length.
Sticky Footer Layout
<!DOCTYPE html>
<html>
<head>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    html, body { height: 100%; font-family: Arial, sans-serif; }
    body {
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      background: #f3f4f6;
    }
    header {
      padding: 20px 30px;
      background: white;
      border-bottom: 1px solid #e5e7eb;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    header .logo { font-weight: bold; color: #a855f7; }
    main {
      flex: 1;
      padding: 40px 30px;
      max-width: 800px;
      margin: 0 auto;
      width: 100%;
    }
    main h1 { color: #1a1a2e; margin-bottom: 12px; }
    main p { color: #4b5563; line-height: 1.6; }
    footer {
      padding: 20px 30px;
      background: #1a1a2e;
      color: #94a3b8;
      text-align: center;
      font-size: 14px;
    }
  </style>
</head>
<body>
  <header>
    <div class="logo">Ishaan.dev</div>
    <div>v1.0</div>
  </header>
  <main>
    <h1>Short Page</h1>
    <p>Even with very little content, the footer stays at the bottom of the viewport because of flexbox.</p>
    <p>This works by making body a flex column that is at least 100vh tall. The main element grows (flex: 1) to fill all leftover space, pushing the footer down.</p>
  </main>
  <footer>
    Made with flexbox by Ishaan - 2026
  </footer>
</body>
</html>
The body is a flex column with min-height: 100vh. The main element has flex: 1, meaning it grows to fill any leftover vertical space. The footer is pushed to the bottom even when the page has minimal content. This replaces the old sticky footer hacks.
A page with a header, short main content, and a footer that is always pinned to the bottom of the viewport even with little content.
Order and align-self
<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: Arial, sans-serif; padding: 30px; background: #f3f4f6; }
    .row {
      display: flex;
      gap: 12px;
      padding: 20px;
      background: white;
      border-radius: 12px;
      margin-bottom: 20px;
      min-height: 120px;
      align-items: center;
    }
    .item {
      width: 80px;
      height: 60px;
      background: #a855f7;
      color: white;
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: bold;
    }
    .first { order: -1; background: #06b6d4; }
    .last  { order: 10; background: #f59e0b; }
    .tall  { height: 100px; }
    .top    { align-self: flex-start; }
    .bottom { align-self: flex-end; }
    h3 { color: #4b5563; margin: 0 0 8px; font-size: 14px; }
  </style>
</head>
<body>
  <h3>order: rearrange visually without changing HTML. Cyan is first, amber is last.</h3>
  <div class="row">
    <div class="item">A</div>
    <div class="item first">B</div>
    <div class="item">C</div>
    <div class="item last">D</div>
    <div class="item">E</div>
  </div>

  <h3>align-self: override align-items on individual items</h3>
  <div class="row" style="align-items: center;">
    <div class="item top">Top</div>
    <div class="item">Mid</div>
    <div class="item tall">Tall</div>
    <div class="item bottom">Bot</div>
    <div class="item">Mid</div>
  </div>
</body>
</html>
order lets you visually reorder flex items without touching the HTML. Items with lower order come first (default is 0). align-self overrides align-items for individual flex items -- the Top item goes to the top of the container while others stay centered.
Two rows of colored boxes. The first shows reordering (cyan first, amber last), the second shows individual items aligned to the top, center, and bottom.

Common Mistakes

Applying Flex Properties to the Wrong Element

.item {
  display: flex;
  justify-content: center;
}
/* This makes .item a flex container for ITS children. */
/* It does not affect how .item itself is aligned. */
display: flex on an item does not move the item itself. It only affects the item's children.
.container {
  display: flex;
  justify-content: center; /* aligns .item within the container */
}
.item {
  /* whatever */
}
display: flex is always applied to the parent. The parent's children are the flex items that get aligned. Put display: flex on the thing containing what you want to align.

Confusing justify-content and align-items

.row {
  display: flex;
  align-items: center;      /* vertically centers, NOT horizontally */
  justify-content: center;  /* horizontally centers, NOT vertically */
}
/* Swapping these causes confusion in flex-direction: column */
In a row, justify-content is horizontal and align-items is vertical. In a column, they SWAP -- justify-content becomes vertical and align-items becomes horizontal. This trips up beginners.
/* Always think: justify-content = MAIN axis, align-items = CROSS axis */
/* The axes rotate with flex-direction. */
Never memorize 'justify = horizontal'. Memorize 'justify = main axis'. Then remember: row main axis is horizontal, column main axis is vertical.

Using Margins Instead of gap

.item {
  margin-right: 20px; /* extra margin on the last item too */
}
.item:last-child { margin-right: 0; } /* ugly fix */
Margins on flex items create uneven spacing at the edges and require last-child hacks.
.container {
  display: flex;
  gap: 20px; /* clean, simple, works everywhere */
}
gap is supported in all modern browsers. It only adds space BETWEEN items (not at the edges) and requires no hacks. Always use gap for spacing flex items.

Forgetting flex-wrap on Responsive Layouts

.grid { display: flex; }
.card { flex: 1 1 240px; }
/* On narrow screens, cards shrink to tiny widths instead of wrapping */
Without flex-wrap, items try to squeeze onto a single line, shrinking past their flex-basis.
.grid {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}
.card { flex: 1 1 240px; }
Add flex-wrap: wrap whenever you want items to flow onto new lines on smaller screens. It is essential for responsive card grids.

Summary

  • display: flex makes an element a flex container. Its direct children become flex items that can be aligned, distributed, wrapped, and ordered with a few properties.
  • Flexbox has a MAIN axis (direction of flow, horizontal by default) and a CROSS axis (perpendicular). flex-direction changes which axis is which.
  • justify-content aligns items along the MAIN axis. Values: flex-start, flex-end, center, space-between (for navbars), space-around, space-evenly.
  • align-items aligns items along the CROSS axis. Values: stretch (default), flex-start, flex-end, center (for vertical centering), baseline.
  • The holy grail of centering: display: flex; justify-content: center; align-items: center. Centers any child both horizontally and vertically.
  • flex-wrap: wrap lets items flow onto multiple lines when they do not fit. Essential for responsive card grids.
  • gap is the modern way to space flex items. Works inside the container, adds space only between items (not at edges), and is far simpler than using margins.
  • flex-grow, flex-shrink, and flex-basis control how items size. The flex shorthand combines them. flex: 1 is the most common value -- it means grow to fill available space.
  • order lets you visually rearrange items without changing the HTML. Useful for responsive layouts where the visual order differs from the source order.
  • Common patterns to memorize: centering (justify + align center), navbar (space-between), card grid (flex: 1 + flex-wrap), sticky footer (flex column + flex: 1 on main).

Ready to Practice?

Test your understanding with 50+ practice questions on this topic.

Go to Practice Questions

Want to learn web development with a live mentor?

Explore our Frontend Masterclass