March 26, 20265 min read

CSS Flexbox: The Only Guide You Actually Need

A practical flexbox tutorial focused on the mental model and the properties you'll use every day, with common layout patterns.

css flexbox layout web-development
Ad 336x280

Flexbox has been around for over a decade now and it's still the most useful layout tool in CSS. Grid is great for two-dimensional layouts, but for most day-to-day work -- navbars, card rows, centering things, spacing items -- flexbox is what you reach for.

The Mental Model

Everything in flexbox comes down to two axes:

  • Main axis: the direction items flow (horizontal by default)
  • Cross axis: perpendicular to the main axis (vertical by default)
When you set display: flex on a container, its children become flex items that line up along the main axis. That's it. Every flexbox property is about controlling how items are placed, sized, and spaced along these two axes. flex-direction sets which axis is "main":
  • row (default): main axis is horizontal, left to right
  • column: main axis is vertical, top to bottom
  • row-reverse and column-reverse: same but flipped
Once you internalize "main axis vs cross axis," every other property clicks into place.

The Properties That Matter

On the Container (Parent)

justify-content -- controls spacing along the main axis.
.container {
  display: flex;
  justify-content: space-between; / items pushed to edges, equal space between /
}

The values you'll actually use:


  • flex-start (default) -- items packed to the start

  • center -- items centered

  • space-between -- first item at start, last at end, equal gaps between

  • space-evenly -- equal space everywhere, including edges

  • flex-end -- items packed to the end


align-items -- controls alignment along the cross axis.

.container {
  display: flex;
  align-items: center; / vertically centers items (when direction is row) /
}

The values you'll use:


  • stretch (default) -- items stretch to fill the container's cross-axis

  • center -- items centered on the cross axis

  • flex-start / flex-end -- items aligned to start/end of cross axis


gap -- space between items. This replaced the old hack of using margins.

.container {
  display: flex;
  gap: 16px;
}

Clean, simple, no weird margin-collapsing behavior. Use it.

flex-wrap -- whether items can wrap to the next line.
.container {
  display: flex;
  flex-wrap: wrap;
}

Without this, flex items will shrink to fit on one line no matter what. Set wrap when you want items to flow to the next row.

On the Items (Children)

flex-grow -- how much an item should grow relative to siblings.
.sidebar { flex-grow: 0; }  / don't grow /
.content { flex-grow: 1; }  / take all remaining space /
flex-shrink -- how much an item should shrink when space is tight. Default is 1 (items shrink equally). Set to 0 if an item should never shrink. flex-basis -- the starting size before grow/shrink kicks in. Think of it as a "suggested width" (or height, if direction is column).

The shorthand flex combines all three:

.item { flex: 1; }          / grow: 1, shrink: 1, basis: 0 /
.item { flex: 0 0 300px; }  / don't grow, don't shrink, always 300px /
align-self -- override align-items for a single item.

Common Layout Patterns

Centering (The Classic)

.center-me {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh; / or whatever height /
}

Two lines of actual layout code. This is the reason flexbox exists.

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

Logo on the left, navigation links on the right. No floats, no positioning hacks.

Card Grid That Wraps

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

.card {
flex: 0 0 calc(33.333% - 14px); / 3 columns with gap accounted for /
}

For truly responsive grids, CSS Grid with auto-fill / minmax is better. But this flexbox approach works fine for simpler cases.

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

main {
flex: 1; / main content grows to fill available space /
}

footer {
/ footer stays at the bottom naturally /
}

The flex: 1 on main makes it absorb all the leftover vertical space, pushing the footer down.

Input with Button

.search-bar {
  display: flex;
}

.search-bar input {
flex: 1; / input grows to fill space /
}

.search-bar button {
flex: 0 0 auto; / button stays its natural size /
}

Properties You Can Mostly Ignore

  • order -- reorders items visually. Breaks tab order and accessibility. Rearrange your HTML instead.
  • align-content -- only matters when you have wrapping items AND extra space on the cross axis. Rare.
  • flex-flow -- shorthand for flex-direction + flex-wrap. Just write them separately; it's more readable.

Debugging Flexbox

Browser DevTools are your best friend here. In Chrome and Firefox, when you select a flex container in the Elements panel, you'll see a "flex" badge. Click it to get a visual overlay showing the axes, gaps, and how space is distributed.

If something isn't working:


  1. Check that the parent has display: flex (not the child)

  2. Check flex-direction -- your "horizontal" property might actually be controlling the vertical axis

  3. Check if items are overflowing because you forgot flex-wrap: wrap

  4. Check if flex-basis or a width/min-width is overriding what you expect


Practice

Flexbox is one of those things where reading about it gets you 30% of the way and actually building layouts gets you the rest. Open CodeUp, fire up the CSS exercises, and build these patterns from scratch. Once you've centered a div with flexbox a dozen times, it becomes second nature.

Ad 728x90