Senior 6 min · March 05, 2026

CSS Flexbox — Why flex-wrap Defaults Break Mobile Grids

Flexbox defaults to nowrap, causing card overlaps below 480px.

N
Naren Founder & Principal Engineer

20+ years shipping production JavaScript and front-end systems at scale. Everything here is grounded in real deployments.

Follow
Production
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Flexbox is a one-dimensional layout model that distributes space along a main axis.
  • The flex container (display: flex) controls the layout of its direct children.
  • justify-content aligns items on the main axis; align-items on the cross axis.
  • flex: 1 is shorthand for grow/shrink/basis: items share space equally.
  • flex-wrap: wrap + flex-basis creates responsive grids without media queries.
  • Biggest mistake: putting alignment properties on the wrong element — always on the container.
✦ Definition~90s read
What is CSS Flexbox Complete?

CSS Flexbox is a one-dimensional layout model designed to distribute space and align content within a container, even when the size of items is unknown or dynamic. It solves the fundamental problem of building responsive interfaces without relying on floats, inline-block hacks, or complex JavaScript calculations.

Imagine you're packing books onto a shelf.

Flexbox operates along two axes—main and cross—giving you precise control over item placement, sizing, and wrapping behavior. It's the go-to tool for component-level layouts like navigation bars, card rows, and form controls, but it's not a replacement for CSS Grid when you need two-dimensional control over rows and columns simultaneously.

The flex-wrap property, while essential for allowing items to flow onto multiple lines, defaults to nowrap, which forces all children onto a single line—a common pitfall that breaks mobile grids by causing horizontal overflow or squished content. Understanding how flex-wrap interacts with flex-basis, flex-grow, and flex-shrink is critical for building layouts that gracefully degrade on small screens.

Real-world usage spans every major framework: Bootstrap 4+ uses Flexbox for its grid system, Tailwind CSS provides utility classes for flex properties, and React Native relies on Flexbox as its default layout engine. When you need to center a child vertically, create equal-height columns, or build a sticky footer, Flexbox delivers with minimal code—but misuse of wrapping defaults can silently destroy mobile layouts, which is why mastering its behavior is non-negotiable for production work.

Plain-English First

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. It's not a replacement for CSS Grid — it's a complementary tool for distributing space in one direction.

Why flex-wrap Defaults Break Mobile Grids

CSS Flexbox is a one-dimensional layout model that distributes space along a main axis and aligns items along a cross axis. Its core mechanic is the flex container, which controls the sizing, ordering, and wrapping of its children via properties like flex-direction, flex-wrap, and justify-content. The default value of flex-wrap is nowrap, meaning all flex items are forced onto a single line, even if they overflow the container. This default is the root cause of many mobile layout bugs. In practice, the key properties are flex-grow, flex-shrink, and flex-basis, which together determine how items expand, contract, or maintain their size. Setting flex-wrap: wrap allows items to flow onto multiple lines, but without explicit flex-basis values, items may shrink unpredictably or leave uneven gaps. Use Flexbox when you need dynamic alignment within a single row or column, such as navigation bars, card rows, or form controls. It is not a replacement for CSS Grid, which handles two-dimensional layouts. Understanding the interplay between flex-basis and wrapping is critical for responsive designs that degrade gracefully on narrow viewports.

nowrap is the default
If you don't set flex-wrap: wrap, items will overflow horizontally on small screens — the most common cause of horizontal scroll on mobile.
Production Insight
A product grid with 4 items per row on desktop uses flex: 0 0 25% and no flex-wrap. On a 320px phone, each item is 80px wide, causing overflow and a horizontal scrollbar.
Symptom: The grid appears broken on mobile — items are cut off or force the page to scroll sideways.
Rule of thumb: Always set flex-wrap: wrap on any flex container that should adapt to smaller viewports, and use flex-basis with min-width to prevent items from shrinking below usable size.
Key Takeaway
Flexbox is one-dimensional — use it for rows or columns, not full page grids.
flex-wrap: wrap is required for responsive layouts; nowrap is the default and will overflow.
Set flex-basis explicitly to control item sizes; relying on content-based sizing leads to unpredictable wrapping.
CSS Flexbox: Mobile Grids & flex-wrap Defaults THECODEFORGE.IO CSS Flexbox: Mobile Grids & flex-wrap Defaults How flex-wrap breaks mobile layouts and how to fix it Flex Container & Children Container sets display:flex; children are flex items Main & Cross Axes Main axis = flex-direction; cross axis = perpendicular justify-content & align-items Align along main and cross axes respectively flex-grow, flex-shrink, flex-basis Control item sizing and responsiveness flex-wrap Default Breaks Grids Wrapping items can cause uneven rows on mobile Auto-Margin Hack Use margin:auto to align items without parent ⚠ flex-wrap:wrap may create gaps on small screens Set flex-basis or use min-width to control wrapping THECODEFORGE.IO
thecodeforge.io
CSS Flexbox: Mobile Grids & flex-wrap Defaults
Css Flexbox Complete Guide

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.htmlCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!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.
Production Insight
A common production bug: applying display: flex to a child element to 'help it align' and wondering why nothing changes.
The container property must be on the parent — always.
DevTools 'Computed' tab shows if an element is a flex container.
Key Takeaway
display: flex goes on the parent.
Only direct children become flex items.
This is the #1 rule beginners miss and it causes most layout confusion.

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.htmlCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!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.
Production Insight
When flex-direction is column, justify-content moves items vertically, align-items horizontally — the opposite of what most expect.
I've seen production UIs where a vertical menu's items were centred horizontally instead of vertically because the developer forgot the axis swap.
Always draw the two axes on a whiteboard before writing code.
Key Takeaway
justify-content controls main axis, align-items controls cross axis.
When flex-direction changes, the axes swap — properties do not change.
Draw axes first, write code second.

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.htmlCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<!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.
Production Insight
In production, I've seen justify-content: space-between used on a container with only one item — it gets pinned to one side, which is confusing.
Always check the number of items when using space-between.
align-self is heavily used in component libraries to handle exceptions like 'the last card has less content'.
Key Takeaway
justify-content and align-items go on the container.
align-self goes on the item — overrides align-items for that one child.
The centring trick is the #1 Flexbox interview answer.

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.htmlCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<!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.</n></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.
Production Insight
Flex-shrink is often forgotten. On a very narrow screen, items with flex: 1 1 auto can shrink to 0 width — making them invisible.
Always provide a min-width or use flex-basis instead of auto for critical items.
The responsive grid pattern with flex-wrap is used by almost every production design system.
Key Takeaway
flex: 1 = flex-grow:1, flex-shrink:1, flex-basis:0%.
flex: 0 0 200px = fixed width sidebar.
flex-wrap: wrap + flex-basis = responsive grid without media queries.

Advanced Techniques: order, align-content, and gap

Once you've mastered the core properties, three advanced features give you finer control: order, align-content, and the gap shorthand.

order lets you reorder flex items visually without changing the HTML. All items have order: 0 by default. Set order: -1 to move an item to the front, or order: 1 to move it to the end. Use it for accessibility-friendly source order reordering — but don't rely on it for logical tab order (keyboard users follow DOM order, not visual order).

align-content controls spacing between rows of wrapped items. It only works when flex-wrap: wrap is active AND items have wrapped onto multiple lines. Values: flex-start, flex-end, center, space-between, space-around, stretch. If your items are all on one line, align-content has no effect.

gap is a shorthand for row-gap and column-gap (or gap in both directions). It adds fixed spacing between flex items, replacing the old hack of using margins on items. gap is supported in all modern browsers and is the cleaner solution.

flexbox-advanced.htmlCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Flexbox Advanced — order, align-content, gap</title>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: sans-serif; padding: 24px; background: #f7fafc; }

    /* ── ORDER EXAMPLE: Reorder cards without changing HTML ──── */
    .order-demo {
      display: flex;
      gap: 12px;
      margin-bottom: 32px;
    }

    .order-demo .card {
      flex: 1;
      padding: 20px;
      background: white;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
    }

    .order-demo .card:nth-child(1) { order: 2; }
    .order-demo .card:nth-child(2) { order: 3; }
    .order-demo .card:nth-child(3) { order: 1; }

    /* ── ALIGN-CONTENT EXAMPLE ──────────────────────────────── */
    .align-content-demo {
      display: flex;
      flex-wrap: wrap;
      align-content: space-around; /* Space between rows of wrapped items */
      height: 300px;
      background: #edf2f7;
      gap: 8px;
      padding: 8px;
      margin-bottom: 32px;
    }

    .align-content-demo .item {
      flex: 0 0 150px;
      height: 60px;
      background: #63b3ed;
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 4px;
    }

    /* ── GAP SHORTHAND ──────────────────────────────────────── */
    .gap-demo {
      display: flex;
      flex-wrap: wrap;
      gap: 24px 16px; /* row-gap:24px, column-gap:16px */
      background: #fefcbf;
      padding: 16px;
    }

    .gap-demo .item {
      flex: 1 1 200px;
      background: white;
      padding: 16px;
      border-radius: 4px;
    }
  </style>
</head>
<body>

  <!-- ORDER: HTML order is 1,2,3 but visual order is 3,1,2 -->
  <div class="order-demo">
    <div class="card">Card 1 (order:2)</div>
    <div class="card">Card 2 (order:3)</div>
    <div class="card">Card 3 (order:1)</div>
  </div>
  <p style="margin-bottom: 32px;">Visual order: Card 3, Card 1, Card 2</p>

  <!-- ALIGN-CONTENT: Rows spaced evenly in container -->
  <div class="align-content-demo">
    <div class="item">Item 1</div>
    <div class="item">Item 2</div>
    <div class="item">Item 3</div>
    <div class="item">Item 4</div>
    <div class="item">Item 5</div>
    <div class="item">Item 6</div>
  </div>
  <p style="margin-bottom: 32px;">Items wrap onto two rows; space-around distributes rows vertically.</p>

  <!-- GAP: separate row and column gaps -->
  <div class="gap-demo">
    <div class="item">Item A</div>
    <div class="item">Item B</div>
    <div class="item">Item C</div>
    <div class="item">Item D</div>
  </div>
  <p>24px vertical gap, 16px horizontal gap between items.</p>
</body>
</html>
Output
First section: Three cards displayed in visual order Card 3, Card 1, Card 2 despite HTML order being 1,2,3. Second section: Blue boxes wrapped onto two rows, vertically spaced with space-around within the container. Third section: Four cards with different gap sizes between rows and columns.
Accessibility Gotcha:
Changing order with CSS does NOT change the keyboard tab order or screen reader reading order. Use it only for visual reordering — never for logical content flow. If the sequence matters for navigation, modify the DOM or use tabindex carefully.
Production Insight
I've seen teams use order to reorder items for responsive breakpoints — then discover keyboard users get lost because tab order doesn't match.
Also, align-content does nothing if all items are on one line. Many developers add it and wonder why it's ignored.
Gap replaces margin hacks; it's 2026 — use gap everywhere.
Key Takeaway
order changes visual order only — not tab order.
align-content works only when flex-wrap wraps onto multiple rows.
Shorthand gap: row-gap column-gap — clean, modern spacing.

flex: The One Property to Rule Them All (and Why Your Shorthand is Off)

Stop writing flex-grow, flex-shrink, and flex-basis separately. That's three chances to forget a zero. Flexbox gives you a single shorthand: flex. The default is flex: 0 1 auto—which means items don't grow, they shrink if needed, and their initial size comes from content. Most juniors override this with flex: 1 and wonder why everything collapses. flex: 1 is flex: 1 1 0—it forces equal distribution by crushing flex-basis to zero. Your 300px sidebar? Gone. The real pattern: use flex: 1 1 0 for equal siblings, flex: 0 0 200px for fixed sidebars, and flex: 1 1 auto when you want items to size from content but still grow. Memorize these three. Everything else is debugging somebody else's incident.

layout.cssCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* Correct pattern for equal-width cards */
.card-list {
  display: flex;
  gap: 1rem;
}

.card {
  flex: 1 1 0; /* grow, shrink, start at 0 */
  min-width: 0; /* prevent overflow in flex children */
}

.sidebar {
  flex: 0 0 250px; /* never grow, never shrink, fixed 250px */
}

.content-area {
  flex: 1 1 500px; /* grow, shrink, base 500px */
}
Output
/* .card elements now share remaining space equally.
.sidebar stays 250px no matter what.
.content-area tries for 500px but can shrink. */
Production Trap:
Setting flex: 1 without a min-width: 0 on children causes flex items to overflow their container. That's the #1 cause of horizontal scrollbars in flex layouts. Add min-width: 0 as a reflex.
Key Takeaway
Use the flex shorthand with all three values. flex: 1 1 0 for equal columns, flex: 0 0 <size> for fixed items, flex: 1 1 auto for content-aware sizing.

The Auto-Margin Hack: Align Items Without Parents Getting Involved

You know `justify-content: space-between pushes the last item to the edge. But what if you need one item to float right inside a row? The flex gospel says use margin-left: auto. This is the unsung hero of flexbox alignment. When you apply margin: auto to a flex item, it consumes all available free space in its direction. Left margin auto? Item shoves right. Top margin auto? Item sinks to the bottom. This works because auto margins in flexbox act like springs—they absorb leftover space. Stop nesting divs just to push a button to the right. One margin property on the child does it. The only caveat: auto margins override align-items and justify-content for that specific item. So if your justify-content: center isn't working on one child, check if there's a sneaky margin: 0 auto` in your CSS.

navigation.cssCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.toolbar {
  display: flex;
  align-items: center;
  padding: 0.5rem 1rem;
  background: #1a1a2e;
  color: white;
}

.logo {
  font-weight: bold;
}

.search {
  flex: 1 1 300px; /* grows to fill space */
}

.action-btn {
  margin-left: auto; /* pushes this button and everything after it to the right */
}

.profile {
  margin-left: 1rem; /* sits next to action-btn */
}
Output
/* .logo on left, .search centers, .action-btn and .profile on far right.
No nested flex containers needed. */
Senior Shortcut:
Pair margin-left: auto with justify-content: flex-start (the default). If you use justify-content: center, the auto margin eats the center space and breaks alignment.
Key Takeaway
margin: auto on a flex item is the simplest one-line solution for pushing items apart within the same flex container.
● Production incidentPOST-MORTEMseverity: high

The Card Grid That Overlapped on Mobile

Symptom
Product cards overlapped horizontally; content was unreadable below 480px width.
Assumption
The team assumed Flexbox would automatically wrap items when container width decreased.
Root cause
The card container had no flex-wrap property (default nowrap), and each card had flex-shrink: 0 to prevent squishing. Flexbox tried to keep all cards on one line, causing horizontal overflow.
Fix
Added flex-wrap: wrap to the container and removed flex-shrink: 0 from cards. Used flex: 1 1 250px on each card to allow wrapping at a sensible width.
Key lesson
  • Never assume Flexbox wraps by default — always set flex-wrap: wrap for row-based grids.
  • Avoid flex-shrink: 0 on items unless you absolutely need fixed widths.
  • Test responsive layouts at the smallest breakpoint first; overflow is silent.
Production debug guideA step-by-step guide to diagnosing misalignment, overflow, and missing responsiveness4 entries
Symptom · 01
Items are not aligning as expected (e.g., justify-content: center does nothing)
Fix
Check the parent has display: flex. Open DevTools, inspect the container, confirm it's a flex container in the computed styles. If it's not a container, the property is silently ignored.
Symptom · 02
Items overflow horizontally or are clipped
Fix
Check for missing flex-wrap. If flex-wrap is nowrap (default), items will shrink or overflow. Add flex-wrap: wrap and ensure items have a min-width or flex-basis.
Symptom · 03
Items appear stacked vertically instead of in a row
Fix
Default flex-direction is row. If items stack, check for flex-direction: column in parent styles. Could be from a media query or inherited from a parent flex container.
Symptom · 04
One item is taller/shorter than others in a row
Fix
align-items defaults to stretch, making all items same height. Check if that item has align-self set, or if its content is block-level causing extra height. Use align-items: flex-start to disable stretch.
★ Flexbox Quick Debug SheetWhen your flex layout breaks, run these checks in order.
Alignment property ignored
Immediate action
Verify parent has display: flex
Commands
Inspect parent element in DevTools → Computed → 'display'
Ensure no flex-direction: column if you expect horizontal alignment
Fix now
Add display: flex to the parent (if missing)
Items don't wrap on small screens+
Immediate action
Check if flex-wrap is set to wrap
Commands
Inspect container → Styles → scroll to 'flex-wrap'
Add flex-wrap: wrap and a flex-basis or min-width on items
Fix now
Add flex-wrap: wrap to container
One item refuses to match height of siblings+
Immediate action
Look for align-self on that item
Commands
Inspect that item → Styles → align-self
Remove align-self or set it to stretch
Fix now
Remove align-self from that item
Content overflows container (scrollbar appears)+
Immediate action
Check flex-shrink values and container overflow
Commands
Inspect container → check overflow property (default visible)
Set overflow: hidden temporarily to see actual child sizes
Fix now
Add flex-wrap: wrap and remove overflow: hidden
Flexbox vs CSS Grid
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

1
display
flex goes on the PARENT container — that one rule makes all direct children into flex items automatically.
2
justify-content controls the MAIN axis, align-items controls the CROSS axis
and those axes SWAP when flex-direction changes to column.
3
flex
1 is the most powerful shorthand you'll write — it means 'grow and shrink equally with siblings', producing fluid layouts without hardcoded widths.
4
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.
5
order changes visual order only; tab and screen reader order remain tied to DOM order.
6
Use gap instead of margin hacks for spacing between flex items.

Common mistakes to avoid

3 patterns
×

Putting justify-content on the flex item instead of the container

Symptom
When you apply justify-content: center to a flex item, nothing happens. The property is silently ignored because it only works on flex containers.
Fix
Always put justify-content and align-items on the parent element that has display: flex. Confirm the parent is indeed a flex container using DevTools.
×

Forgetting that flex-direction: column swaps the axes

Symptom
You set justify-content: center expecting to centre items vertically, but they centre horizontally instead.
Fix
Remember that when flex-direction: column, the main axis becomes vertical. justify-content controls vertical alignment in that case. Draw the axes on paper before debugging.
×

Using flex without flex-wrap on card grids

Symptom
On small screens, cards squish into a single overflowing row instead of wrapping to the next line.
Fix
Add flex-wrap: wrap to the container. Provide a min-width or flex-basis on items (e.g., flex: 1 1 250px) so they wrap at a reasonable size.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What's the difference between justify-content and align-items in Flexbox...
Q02SENIOR
How would you build a navigation bar where the logo is on the left and t...
Q03SENIOR
What does flex: 1 actually expand to, and why would you use flex: 0 0 20...
Q01 of 03JUNIOR

What's the difference between justify-content and align-items in Flexbox, and what happens to each when you change flex-direction to column?

ANSWER
justify-content controls the main axis; align-items controls the cross axis. By default, main axis is horizontal (row), so justify-content moves items left/right and align-items moves up/down. When you set flex-direction: column, the main axis becomes vertical — justify-content now controls up/down, and align-items controls left/right. The properties don't change meaning; the axes flip.
FAQ · 3 QUESTIONS

Frequently Asked Questions

01
When should I use Flexbox instead of CSS Grid?
02
Why isn't my justify-content: center working?
03
What's the difference between align-items and align-content?
N
Naren Founder & Principal Engineer

20+ years shipping production JavaScript and front-end systems at scale. Everything here is grounded in real deployments.

Follow
Verified
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
🔥

That's HTML & CSS. Mark it forged?

6 min read · try the examples if you haven't

Previous
CSS Basics and Box Model
3 / 16 · HTML & CSS
Next
CSS Grid Complete Guide