CSSbeginner

Flexbox Complete Guide — From Basics to Mastery

Master CSS Flexbox: alignment, ordering, sizing, wrapping, and real-world layout patterns. The only Flexbox reference you need.

20 min read·Published Mar 3, 2026
cssflexboxlayoutresponsive

What Is Flexbox?

Flexbox (Flexible Box Layout) is a one-dimensional CSS layout model designed to distribute space and align items inside a container — even when their sizes are unknown or dynamic. Before flexbox, developers relied on floats, inline-block hacks, and tables for layout. Flexbox replaced all of that with a clean, predictable system.

.container {
  display: flex;
}

That single line turns the container into a flex container and its direct children into flex items. Nothing else changes — the children simply gain flex superpowers.

The Two Axes

Everything in flexbox revolves around two axes:

Main Axis (flex-direction: row)
-------------------------------------------->
|  [Item 1]  [Item 2]  [Item 3]  [Item 4]  |
<--------------------------------------------

Cross Axis (perpendicular)
|
|  [Item 1]  [Item 2]  [Item 3]
|
v
  • Main axis — the direction items flow. Controlled by flex-direction.
  • Cross axis — perpendicular to the main axis. Always 90 degrees from main.

When flex-direction is row, main axis is horizontal. When column, main axis is vertical. This distinction matters for every alignment property.

flex-direction: row          flex-direction: column

Main ------>                 Main
[A] [B] [C]                   |
     ^                        v
     |                      [A]
   Cross                    [B]
                            [C]
                          Cross -->

Flex Container Properties

These properties go on the parent element — the flex container.

display: flex vs display: inline-flex

/* Block-level flex container — takes full width */
.container {
  display: flex;
}

/* Inline-level flex container — shrinks to content width */
.container-inline {
  display: inline-flex;
}

Use inline-flex when you need the container to sit alongside other inline elements. In practice, display: flex covers 95% of use cases.

flex-direction

Controls the main axis 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 */
}

Common mistake: forgetting that justify-content and align-items swap their visual effect when you switch from row to column. justify-content: center centers horizontally in row mode but vertically in column mode.

justify-content

Aligns items along the main axis.

.container {
  display: flex;
  justify-content: flex-start;    /* packed to start (default) */
  justify-content: flex-end;      /* packed to end */
  justify-content: center;        /* centered */
  justify-content: space-between; /* equal space between items */
  justify-content: space-around;  /* equal space around each item */
  justify-content: space-evenly;  /* truly even spacing everywhere */
}

Visual comparison:

flex-start:     [A][B][C]...............
flex-end:       ...............[A][B][C]
center:         .......[A][B][C].......
space-between:  [A]......[B]......[C]
space-around:   ..[A]....[B]....[C]..
space-evenly:   ...[A]...[B]...[C]...

The difference between space-around and space-evenly:

  • space-around gives each item equal margin on both sides. Edge items have half the gap vs interior items.
  • space-evenly makes every gap identical, including edges.

align-items

Aligns items along the cross axis.

.container {
  display: flex;
  align-items: stretch;     /* default: fill container height */
  align-items: flex-start;  /* top-aligned (in row mode) */
  align-items: flex-end;    /* bottom-aligned */
  align-items: center;      /* vertically centered */
  align-items: baseline;    /* aligned by text baseline */
}
stretch:     |AAAA|BBBBBB|CCC |  (all same height)
flex-start:  |AA  |BBBB  |C   |
flex-end:    |  AA|  BBBB|   C|
center:      | AA |  BB  | C  |
baseline:    |Aa  |Bb    |Cc  |  (text baselines align)

baseline is underused. When you have items with different font sizes and want their text to line up, baseline is the answer.

align-content

Controls spacing between wrapped lines (only works with flex-wrap: wrap).

.container {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;    /* lines packed to top */
  align-content: flex-end;      /* lines packed to bottom */
  align-content: center;        /* lines centered */
  align-content: space-between; /* equal space between lines */
  align-content: space-around;  /* equal space around lines */
  align-content: stretch;       /* lines stretch to fill (default) */
}

Important: align-content has no effect on single-line flex containers. You need flex-wrap: wrap AND multiple lines for it to do anything.

flex-wrap

Controls whether items wrap to new lines.

.container {
  flex-wrap: nowrap;       /* default: single line, items may shrink */
  flex-wrap: wrap;         /* wrap to new lines below */
  flex-wrap: wrap-reverse; /* wrap to new lines above */
}
nowrap:        [A][B][C][D][E][F] (all squeezed into one line)

wrap:          [A][B][C][D]
               [E][F]

wrap-reverse:  [E][F]
               [A][B][C][D]

flex-flow Shorthand

Combines flex-direction and flex-wrap:

.container {
  flex-flow: row nowrap;      /* default */
  flex-flow: column wrap;     /* vertical with wrapping */
  flex-flow: row-reverse wrap; /* reversed horizontal with wrapping */
}

gap

Adds spacing between flex items. This is the modern replacement for margin hacks.

.container {
  display: flex;
  gap: 16px;          /* equal row and column gap */
  row-gap: 16px;      /* gap between rows (when wrapping) */
  column-gap: 8px;    /* gap between columns */
}

Before gap, developers used margins with negative margins on the container, or :last-child selectors to remove trailing margins. gap solves this cleanly.

/* OLD approach (avoid) */
.item { margin-right: 16px; }
.item:last-child { margin-right: 0; }

/* MODERN approach */
.container { display: flex; gap: 16px; }

Browser support for gap in flexbox is excellent — supported in all modern browsers since 2021. Safe to use in production.

Flex Item Properties

These properties go on the children — the flex items.

flex-grow

How much an item should grow relative to its siblings when there is extra space.

.item-a { flex-grow: 0; }  /* default: don't grow */
.item-b { flex-grow: 1; }  /* take remaining space */
.item-c { flex-grow: 2; }  /* take 2x as much remaining space as item-b */
Container: [........................................]
                   400px total, items need 200px

flex-grow: 0, 1, 2
[AAA (fixed)][BBBBBBB (67px extra)][CCCCCCCCCCCCCC (133px extra)]

The 200px of remaining space is divided:
  - A gets 0 shares (stays at content width)
  - B gets 1/3 = 67px extra
  - C gets 2/3 = 133px extra

flex-shrink

How much an item should shrink when the container is too small.

.item { flex-shrink: 1; }  /* default: shrink proportionally */
.item { flex-shrink: 0; }  /* never shrink — content may overflow */
.item { flex-shrink: 3; }  /* shrink 3x as aggressively */

flex-shrink: 0 is useful for fixed-size elements like icons or buttons that should never compress.

flex-basis

The initial size of an item before flex-grow or flex-shrink kicks in.

.item { flex-basis: auto; }   /* default: use width/height or content */
.item { flex-basis: 200px; }  /* start at 200px, then grow/shrink */
.item { flex-basis: 50%; }    /* start at 50% of container */
.item { flex-basis: 0; }      /* ignore content size completely */

How flex-basis differs from width:

  • flex-basis is a suggestion — flexbox may override it via grow/shrink.
  • width is a constraint but flex-basis takes priority when both are set.
  • In flex-direction: column, flex-basis acts like height.

The flex Shorthand

The flex shorthand is the recommended way to set grow, shrink, and basis together.

.item { flex: initial; }    /* 0 1 auto — don't grow, can shrink */
.item { flex: auto; }       /* 1 1 auto — grow and shrink freely */
.item { flex: none; }       /* 0 0 auto — rigid, no flex at all */
.item { flex: 1; }          /* 1 1 0% — grow equally, ignore content */
.item { flex: 2; }          /* 2 1 0% — grow 2x, ignore content */
.item { flex: 0 1 auto; }   /* explicit default values */
.item { flex: 2 0 200px; }  /* grow 2x, don't shrink, start at 200px */

Important gotcha: flex: 1 sets flex-basis: 0%, not auto. This means content size is ignored and all items get truly equal widths. If you want items to respect their content size while still growing, use flex: 1 1 auto.

/* Equal widths regardless of content */
.equal-items { flex: 1; }  /* basis: 0% */

/* Proportional to content, but fill remaining space */
.proportional-items { flex: 1 1 auto; }  /* basis: auto */

align-self

Override the container's align-items for a single item.

.container {
  display: flex;
  align-items: flex-start;
}

.special-item {
  align-self: flex-end;   /* this one goes to the bottom */
}
.centered-item {
  align-self: center;     /* this one centers vertically */
}

Possible values: auto (inherit from container), flex-start, flex-end, center, baseline, stretch.

order

Change visual order without modifying HTML. Default is 0.

.sidebar  { order: 1; }  /* visually first */
.main     { order: 2; }  /* visually second */
.aside    { order: 3; }  /* visually third */

Accessibility warning: order changes only the visual order. Screen readers and keyboard navigation still follow DOM order. Use sparingly and only when the visual reorder doesn't break the logical reading flow.

/* Responsive reordering — mobile shows main content first */
@media (max-width: 768px) {
  .sidebar { order: 2; }
  .main    { order: 1; }
}

Real-World Layout Patterns

1. Perfect Centering

The most common flexbox use case. Center anything horizontally and vertically.

.center-everything {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

For centering a single child, you can also use margin: auto on the item:

.container {
  display: flex;
  min-height: 100vh;
}

.centered-child {
  margin: auto; /* centers in both axes */
}

2. Navigation Bar

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 1rem;
  height: 60px;
}

.nav-left {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav-right {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
[Logo  Home  About]                    [Search  Login]
|--- nav-left -----|                   |-- nav-right -|
|--------------- space-between -----------------------|

3. Responsive Card Layout

.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.card {
  flex: 1 1 300px;  /* grow, shrink, min 300px */
  max-width: 100%;  /* prevent overflow on mobile */
}

This pattern creates cards that are at least 300px wide, grow to fill available space, and wrap to new rows when the container gets narrow. No media queries needed.

Page footer that stays at the bottom even with short content.

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

.header  { /* natural height */ }
.content { flex: 1; }  /* grows to push footer down */
.footer  { /* natural height, always at bottom */ }
+------------------+
|     Header       |
+------------------+
|                  |
|    Content       |  <- flex: 1 (fills remaining space)
|                  |
|                  |
+------------------+
|     Footer       |  <- always at bottom
+------------------+
.input-group {
  display: flex;
  max-width: 500px;
}

.input-group input {
  flex: 1;            /* takes all available space */
  min-width: 0;       /* allows shrinking below content size */
  padding: 0.5rem;
}

.input-group button {
  flex-shrink: 0;     /* button never shrinks */
  padding: 0.5rem 1rem;
}

The min-width: 0 on the input is critical. By default, flex items have min-width: auto, which prevents them from shrinking below their content size. For inputs and elements with text, this can cause overflow.

6. Sidebar Layout

.app-layout {
  display: flex;
  min-height: 100vh;
}

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

.main-content {
  flex: 1;             /* fills remaining space */
  min-width: 0;        /* prevents overflow from wide content */
}

/* Collapse sidebar on mobile */
@media (max-width: 768px) {
  .app-layout {
    flex-direction: column;
  }
  .sidebar {
    flex-basis: auto;  /* natural height in column mode */
  }
}

7. Equal Height Cards

One of flexbox's best features — child elements automatically match the tallest sibling's height.

.card-row {
  display: flex;
  gap: 1rem;
}

.card {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.card-body {
  flex: 1;  /* pushes footer to bottom of card */
}

.card-footer {
  /* always aligned at bottom across all cards */
}
+----------+  +----------+  +----------+
| Title    |  | Title    |  | Title    |
|          |  |          |  |          |
| Body     |  | Body     |  | Body     |
| (long)   |  | (short)  |  | (medium) |
|          |  |  flex:1   |  |          |
|          |  |  fills    |  |          |
+----------+  +----------+  +----------+
| Footer   |  | Footer   |  | Footer   |
+----------+  +----------+  +----------+

8. Media Object

A classic pattern: image on the left, text on the right.

.media {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
}

.media-image {
  flex-shrink: 0;  /* image never compresses */
  width: 80px;
  height: 80px;
}

.media-body {
  flex: 1;
  min-width: 0;  /* allows text truncation */
}

.media-body h3 {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

9. Holy Grail Layout

The classic three-column layout with header and footer.

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

.page-body {
  display: flex;
  flex: 1;
}

.left-sidebar  { flex: 0 0 200px; }
.main-content  { flex: 1; min-width: 0; }
.right-sidebar { flex: 0 0 200px; }

@media (max-width: 768px) {
  .page-body { flex-direction: column; }
  .left-sidebar,
  .right-sidebar { flex-basis: auto; }
}

10. Masonry-Like Columns

While not true masonry, flexbox can create a column-based layout.

.masonry {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.masonry-column {
  flex: 1 1 300px;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

Responsive Flexbox Patterns

Mobile-First Navigation

.nav {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

@media (min-width: 768px) {
  .nav {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }
}

Responsive Form

.form-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

@media (min-width: 640px) {
  .form-row {
    flex-direction: row;
    gap: 1rem;
  }
  .form-row label {
    flex: 0 0 120px;
  }
  .form-row input {
    flex: 1;
  }
}

Responsive Feature Grid

.features {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
}

.feature {
  flex: 1 1 250px;  /* responsive without media queries */
}

/* Optional: limit to 3 columns max */
.feature {
  flex: 1 1 calc(33.333% - 2rem);
  max-width: calc(33.333% - 2rem);
}

@media (max-width: 768px) {
  .feature {
    flex: 1 1 100%;
    max-width: 100%;
  }
}

Common Flexbox Mistakes

Mistake 1: Forgetting min-width: 0

Flex items default to min-width: auto, which prevents them from shrinking below their content size. This causes overflow with long text or large images.

/* BUG: long text overflows container */
.item {
  flex: 1;
}

/* FIX: allow shrinking below content size */
.item {
  flex: 1;
  min-width: 0;
}

Mistake 2: Using width Instead of flex-basis

/* Works but less flexible */
.item { width: 200px; }

/* Preferred in flex context */
.item { flex: 0 0 200px; }

Mistake 3: Nesting Too Many Flex Containers

Every display: flex creates a new formatting context. Deep nesting can make layouts fragile and hard to debug.

/* Overly nested — hard to maintain */
.level-1 { display: flex; }
.level-2 { display: flex; }
.level-3 { display: flex; }
.level-4 { display: flex; }

/* Better: flatten structure or use Grid for 2D layouts */

Mistake 4: Ignoring flex-shrink on Fixed Elements

/* BUG: icon shrinks when space is tight */
.icon { width: 24px; }

/* FIX: prevent shrinking */
.icon {
  width: 24px;
  flex-shrink: 0;
}

Mistake 5: Relying on order for Accessibility

/* Visual order: C, A, B */
.item-a { order: 2; }
.item-b { order: 3; }
.item-c { order: 1; }

/* Screen reader still reads: A, B, C (DOM order) */
/* Keyboard tab order: A, B, C (DOM order) */

Always ensure the DOM order makes logical sense. Use order only for minor visual adjustments.

Mistake 6: Using Flexbox When Grid Is Better

Flexbox is one-dimensional. If you need items to align in both rows AND columns, use CSS Grid.

/* Awkward with flexbox — items don't align in columns */
.grid-attempt {
  display: flex;
  flex-wrap: wrap;
}

/* Clean with grid */
.proper-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

Browser Support & Compatibility

Flexbox has excellent browser support. All modern browsers have fully supported it since 2015.

FeatureChromeFirefoxSafariEdge
Basic flexbox29+28+9+12+
flex-wrap29+28+9+12+
gap in flexbox84+63+14.1+84+

The only concern is gap in flexbox contexts — older Safari versions (pre-14.1) don't support it. If supporting older browsers:

/* Fallback for older browsers */
.container {
  display: flex;
  flex-wrap: wrap;
  margin: -0.5rem;
}
.item {
  margin: 0.5rem;
}

/* Modern browsers */
@supports (gap: 1rem) {
  .container {
    gap: 1rem;
    margin: 0;
  }
  .item {
    margin: 0;
  }
}

Debugging Flexbox

Browser DevTools

Every modern browser has flexbox debugging built in:

  1. Chrome/Edge: Inspect element, look for the flex badge. Click it to see overlay.
  2. Firefox: Best flexbox inspector. Shows main/cross axis, item sizes, free space.
  3. Safari: Inspect element, Layout tab shows flex information.

Common Debug Checklist

1. Is the container actually display: flex?
   → Check computed styles

2. Are items overflowing?
   → Check min-width: auto (default)
   → Add min-width: 0 to flex items

3. Items not growing?
   → Check flex-grow (default is 0)
   → Check if max-width is constraining

4. Items not wrapping?
   → Check flex-wrap (default is nowrap)
   → Check if container has a fixed width

5. Alignment not working?
   → Check which axis you're targeting
   → justify-content = main axis
   → align-items = cross axis
   → Verify flex-direction (it changes which axis is which)

Flexbox Interview Questions

Q1: What is the difference between justify-content and align-items?

justify-content aligns items along the main axis (horizontal by default). align-items aligns items along the cross axis (vertical by default). When flex-direction changes, so do the axes.

Q2: What does flex: 1 actually mean?

flex: 1 is shorthand for flex-grow: 1, flex-shrink: 1, flex-basis: 0%. It means the item will grow to fill available space, can shrink, and its initial size is 0 (ignoring content width). This makes all flex: 1 items equal width.

Q3: How do you create equal-width columns with flexbox?

.container { display: flex; }
.column { flex: 1; }

Each column gets the same width regardless of content, because flex: 1 sets flex-basis: 0%.

Q4: What is min-width: auto and why does it matter?

By default, flex items have min-width: auto, which means they refuse to shrink below their content size. This often causes unexpected overflow. Setting min-width: 0 allows the item to shrink below its content size.

Q5: Can you change the visual order of flex items without changing HTML?

Yes, using the order property. Default is 0. Lower values appear first. However, this only changes visual order — screen readers and keyboard navigation still follow DOM order.

Q6: When should you use flexbox vs CSS Grid?

Use flexbox for one-dimensional layouts — a single row or column of items. Use Grid for two-dimensional layouts where items need to align in both rows and columns simultaneously. They can also be combined.

Q7: What is the difference between flex-basis and width?

flex-basis defines the initial size of a flex item before grow/shrink is applied. width is a general CSS property. In a flex context, flex-basis takes priority over width. In flex-direction: column, flex-basis acts as height.

Q8: How does gap differ from margins in flexbox?

gap creates space between items only — not on the edges. Margins add space around each item individually, including edges. gap is cleaner and doesn't require :first-child / :last-child overrides.

Advanced Techniques

Fluid Widths with calc()

/* Three columns with gap accounted for */
.item {
  flex: 0 0 calc(33.333% - 1rem);
}

Flex and Auto Margins

margin: auto in flexbox absorbs all available space in that direction.

.nav {
  display: flex;
  align-items: center;
}

/* Push everything after this item to the right */
.nav-item-push {
  margin-left: auto;
}
[Home] [About] [Blog]         [Login] [Signup]
                      ^
                margin-left: auto pushes these right

Nested Flex Containers

.outer {
  display: flex;
  gap: 1rem;
}

.sidebar {
  flex: 0 0 250px;
}

.main {
  flex: 1;
  display: flex;         /* nested flex */
  flex-direction: column;
  gap: 1rem;
}

.main-header { /* natural height */ }
.main-body   { flex: 1; }
.main-footer { /* natural height */ }

Truncating Text in Flex Items

.flex-item {
  flex: 1;
  min-width: 0;  /* required for truncation to work */
}

.flex-item span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Without min-width: 0 on the flex item, the text will overflow instead of truncating.

Performance Notes

Flexbox layout is fast. The browser calculates flex sizing in a single pass for simple layouts. Performance tips:

  1. Avoid deeply nested flex containers — each level adds a layout calculation.
  2. Use will-change: transform only when animating flex items — not as a default.
  3. flex-wrap: wrap with many items is slightly more expensive than nowrap because the browser must calculate line breaks.
  4. Avoid mixing percentage and pixel flex-basis values in the same container — it complicates the layout algorithm.

In real-world applications, flexbox performance is rarely a bottleneck. Focus on correct layout first, optimize only if you measure a problem.

Quick Reference Table

PropertyApplies ToValues
displaycontainerflex, inline-flex
flex-directioncontainerrow, row-reverse, column, column-reverse
flex-wrapcontainernowrap, wrap, wrap-reverse
justify-contentcontainerflex-start, flex-end, center, space-between, space-around, space-evenly
align-itemscontainerstretch, flex-start, flex-end, center, baseline
align-contentcontainerstretch, flex-start, flex-end, center, space-between, space-around
gapcontainerlength (e.g., 16px, 1rem)
flex-growitemnumber (default 0)
flex-shrinkitemnumber (default 1)
flex-basisitemauto, length, percentage (default auto)
flexitemshorthand for grow shrink basis
align-selfitemauto, flex-start, flex-end, center, baseline, stretch
orderiteminteger (default 0)

Key Takeaways

  • display: flex creates a flex container; direct children become flex items.
  • Main axis is controlled by flex-direction, aligned with justify-content.
  • Cross axis is perpendicular, aligned with align-items (container) or align-self (item).
  • Use flex: 1 for equal-width items that fill available space.
  • Use gap instead of margin hacks for spacing between items.
  • Always add min-width: 0 on flex items that contain text or wide content.
  • Use flex-shrink: 0 on elements that should never compress (icons, buttons).
  • Flexbox is ideal for one-dimensional layouts (rows or columns).
  • For two-dimensional layouts (rows AND columns), use CSS Grid instead.
  • order changes visual order only — DOM order still controls screen readers and keyboard.
  • When debugging, check the axis direction first — flex-direction changes everything.

Found this helpful?

Support devsofus — help us keep creating free dev guides.

Related Articles