CSS Flexbox Guide for Beginners

Learn flexible layouts from zero — with live demos you can see

What You'll Learn

  1. What is Flexbox?
  2. display: flex — Your First Flex Container
  3. flex-direction: row vs column
  4. justify-content — Spacing Items Horizontally
  5. align-items — Centering Vertically
  6. flex-wrap — Handling Overflow
  7. gap — Adding Space Between Items
  8. flex-grow, flex-shrink, flex-basis
  9. Real-World: Centering a Div
  10. Real-World: Responsive Navbar
  11. Real-World: Card Layout
  12. Common Mistakes & Fixes
  13. Next Steps

1. What is Flexbox?

Flexbox (Flexible Box Layout) is a CSS layout system designed to distribute space and align items inside a container. Before Flexbox existed, developers relied on floats, inline-block hacks, and absolute positioning to build layouts. Those techniques were fragile, unintuitive, and required clearing fixes that cluttered your code.

Flexbox solves this by giving you direct control over how items are spaced, aligned, and ordered inside a parent container. You tell the container how to behave, and it figures out the math. No hacks, no clearfixes, no pixel-perfect calculations.

The core idea: you have a flex container (the parent) and flex items (the children). You put display: flex on the parent, and every direct child becomes a flex item. That single line changes everything.

Before & After Flexbox

Without Flexbox
Item 1
Item 2
Item 3

Items stack vertically (default block behavior)

With Flexbox
Item 1
Item 2
Item 3

Items sit side by side automatically

That entire difference comes from one line of CSS: display: flex. The parent becomes a flex container, and its children line up in a row. No floats. No clearfixes. Just flex.

2. display: flex — Your First Flex Container

Every Flexbox layout starts the same way. You pick a parent element and add display: flex to it. That parent is now a "flex container," and every direct child inside it becomes a "flex item."

This is important: Flexbox only affects the direct children of the container. If you have nested elements inside those children, they behave normally unless you also make them flex containers. Flexbox does not cascade down automatically.

.container {
  display: flex;
}

<div class="container">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>
Live Result
Item 1
Item 2
Item 3

Notice how the items immediately jump into a horizontal row. That is the default flex behavior: items flow along the main axis, which is horizontal (left to right) by default. The perpendicular direction is called the cross axis (top to bottom).

Understanding these two axes is the key to understanding everything else in Flexbox. Every property you learn from here on either controls how items are arranged along the main axis or the cross axis.

Tip: You can also use display: inline-flex if you want the container itself to behave like an inline element rather than a block element. The items inside behave the same way.

3. flex-direction: row vs column

The flex-direction property controls which direction the main axis runs. By default it is row, which means items flow left to right. Change it to column and items stack top to bottom instead.

This matters because justify-content always works along the main axis and align-items always works along the cross axis. So when you switch from row to column, the effect of those properties swaps. This catches many beginners off guard.

/* Horizontal (default) */
.container { display: flex; flex-direction: row; }

/* Vertical */
.container { display: flex; flex-direction: column; }
flex-direction: row
A
B
C
flex-direction: column
A
B
C

There are also row-reverse and column-reverse values that flip the order. These are useful for right-to-left layouts or when you want the last item to appear first visually without changing the HTML order.

flex-direction: row-reverse
1st in HTML
2nd in HTML
3rd in HTML
When to use column: Navigation sidebars, form layouts, mobile menus. Whenever items should stack vertically, flex-direction: column is your friend.

4. justify-content — Spacing Items Along the Main Axis

Once your items are in a row (or column), you usually want to control how they are distributed along that axis. That is what justify-content does. It decides whether items clump together at the start, spread out evenly, or center themselves.

There are six values you should know. Each one distributes leftover space differently. The key idea: Flexbox calculates the total width of all items, subtracts that from the container width, and then distributes the remaining space according to the justify-content value.

.container {
  display: flex;
  justify-content: center; /* or flex-start, flex-end,
      space-between, space-around, space-evenly */
}
flex-start (default)
A
B
C
center
A
B
C
flex-end
A
B
C
space-between
A
B
C
space-around
A
B
C
space-evenly
A
B
C

The difference between space-between, space-around, and space-evenly is subtle but matters. space-between puts the first and last items flush against the edges, with equal space between the rest. space-around gives each item equal space on both sides, which means the edges get half the space of the gaps. space-evenly makes every gap identical, including the edges.

Most used: In practice, center and space-between cover 90% of real layouts. Use center for centering things, and space-between for navbars (logo left, links right).

5. align-items — Centering Vertically

While justify-content handles the main axis, align-items handles the cross axis. In a default row layout, the cross axis is vertical. So align-items controls vertical positioning of items within the container.

This is the property that finally makes vertical centering easy. Before Flexbox, vertically centering an element was famously one of the hardest things in CSS. With Flexbox, it is one line: align-items: center.

.container {
  display: flex;
  align-items: center; /* or stretch, flex-start,
      flex-end, baseline */
  height: 150px; /* needs height to see the effect */
}
stretch (default) — items fill the container height
A
B
C
center — items sit in the vertical middle
A
B (taller)
C
flex-start — items align to the top
A
B (taller)
C
flex-end — items align to the bottom
A
B (taller)
C

The stretch default is why flex items automatically fill the full height of their container. If you set explicit heights on items, stretch has no visible effect. The baseline value aligns items by their text baselines, which is useful when items have different font sizes and you want the text to line up.

Important: align-items only has a visible effect when the container is taller than its items. If the container is exactly the height of its content, there is no extra space to distribute. Give the container a set height or min-height to see alignment in action.

6. flex-wrap — Handling Overflow

By default, flex items try to squeeze onto a single line. If you have ten items and the container is narrow, they will all shrink to fit rather than wrapping. This is because flex-wrap defaults to nowrap.

Set flex-wrap: wrap and items that do not fit will move to the next line. This is essential for responsive layouts. Without wrapping, your layouts will overflow or items will become unusably narrow on small screens.

.container {
  display: flex;
  flex-wrap: wrap; /* allow items to wrap to new lines */
}
nowrap (default) — items shrink
One
Two
Three
Four
Five
wrap — items flow to next line
One
Two
Three
Four
Five

When items wrap, you get a multi-line flex container. You can then use align-content (not align-items) to control how those rows are distributed vertically. Think of align-content as justify-content but for the cross axis, and only when there are multiple lines.

Rule of thumb: If your flex container holds a dynamic or unknown number of items (cards, tags, image galleries), always add flex-wrap: wrap. If you have a fixed number of items that should always stay in one row (like a navbar), leave it as nowrap.

7. gap — Adding Space Between Items

Before the gap property existed, developers used margins on flex items to create spacing. The problem with margins is they add space on the outside edges too, which means you need a negative margin on the container or special selectors to remove the extra space from the first and last items.

The gap property solves this cleanly. It only adds space between items, never on the outer edges. It is set on the container, not the items.

.container {
  display: flex;
  gap: 20px;     /* equal row and column gap */
  gap: 20px 10px; /* row-gap column-gap */
}
gap: 0 (no spacing)
A
B
C
gap: 10px
A
B
C
gap: 30px
A
B
C

The gap property works with both Flexbox and CSS Grid, so learning it once pays off twice. You can use any CSS unit: pixels, rems, percentages, or even calc() expressions.

Best practice: Use gap instead of margins for spacing flex items. It is cleaner, more predictable, and supported in all modern browsers. The gap property has been supported in Flexbox since 2020 in every major browser.

8. flex-grow, flex-shrink, flex-basis

These three properties are set on individual flex items (not the container) and control how items grow, shrink, and what their starting size should be. They are often written as a shorthand: flex: grow shrink basis.

flex-basis

flex-basis sets the initial size of a flex item before any growing or shrinking happens. Think of it as a suggestion: "start at this size, then adjust." It works like width in a row layout and like height in a column layout. The default value is auto, which uses the item's content size or explicit width.

flex-grow

flex-grow controls how much of the leftover space an item should absorb. The default is 0, meaning items do not grow beyond their basis. If you set flex-grow: 1 on all items, they share the extra space equally. If one item has flex-grow: 2 and others have 1, it gets twice as much of the extra space.

/* All items share space equally */
.item { flex: 1; } /* shorthand for flex: 1 1 0% */

/* Middle item takes twice the extra space */
.item { flex-grow: 1; }
.item-wide { flex-grow: 2; }
All items flex-grow: 0 (default, no growing)
A
B
C
All items flex-grow: 1 (share space equally)
A
B
C
Item B has flex-grow: 3, others have 1
grow: 1
grow: 3
grow: 1

flex-shrink

flex-shrink is the opposite of flex-grow. It controls how items shrink when the container is too small. The default is 1, meaning all items shrink equally. Set it to 0 on an item to prevent it from shrinking below its basis.

The flex shorthand

In practice, you will almost always use the shorthand. The most common patterns are:

flex: 1;     /* Grow equally, shrink equally, basis 0% */
flex: auto;  /* Grow equally, shrink equally, basis auto */
flex: none;  /* Don't grow, don't shrink, basis auto */
flex: 0 0 200px; /* Fixed 200px, no grow, no shrink */
The most useful pattern: flex: 1 on all items makes them equal width. This is perfect for equal-width columns, form inputs that should fill available space, or any layout where items should share space.

9. Real-World: Centering a Div

This is the single most searched CSS question in history. Before Flexbox, centering a div both horizontally and vertically required hacks involving transforms, table-cell display, or negative margins with absolute positioning. With Flexbox, it takes exactly three lines on the parent.

.parent {
  display: flex;
  justify-content: center; /* horizontal center */
  align-items: center;     /* vertical center */
  height: 100vh;          /* full viewport height */
}

<div class="parent">
  <div class="child">I'm centered!</div>
</div>
Perfectly centered (horizontally and vertically)
I'm centered!

That is it. justify-content: center centers along the main axis (horizontally). align-items: center centers along the cross axis (vertically). The parent needs a defined height, otherwise there is no vertical space to center within. Using height: 100vh makes the parent fill the full viewport.

There is an even shorter alternative using the place-items shorthand or the margin: auto trick:

/* Alternative: auto margins on the child */
.parent { display: flex; height: 100vh; }
.child  { margin: auto; } /* centers in both axes */
Why margin auto works: In a flex container, margin: auto absorbs all available space in every direction. This pushes the item to the dead center. It also works for pushing a single item to the far right: margin-left: auto.

10. Real-World: Responsive Navbar

Navigation bars are one of the most common uses for Flexbox. The typical pattern is: logo on the left, navigation links on the right, everything vertically centered. With Flexbox, this is a single container using space-between.

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

.nav-right {
  display: flex;
  gap: 20px;
}
Navbar Layout
MySite
Home About Blog Contact

The magic here is space-between: it pushes the first child (logo) to the left edge and the last child (nav links) to the right edge. The nav links themselves are also a flex container with gap for spacing.

To make this responsive, use a media query to switch the navbar to flex-direction: column on small screens, or hide the links behind a hamburger menu. The Flexbox structure stays the same either way.

@media (max-width: 600px) {
  .navbar {
    flex-direction: column;
    gap: 12px;
  }
  .nav-right {
    flex-wrap: wrap;
    justify-content: center;
  }
}

11. Real-World: Card Layout

Card grids are everywhere: product listings, blog previews, team pages, portfolios. Flexbox with flex-wrap: wrap creates responsive card layouts that adapt to the screen width without media queries.

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

.card {
  flex: 1 1 250px; /* grow, shrink, min-width 250px */
  padding: 24px;
  border: 1px solid #222;
  border-radius: 12px;
}
Responsive Card Grid
Fast Setup
Get your project running in minutes, not hours. Zero config needed.
🔒
Secure
Built-in security features protect your data from day one.
🎨
Customizable
Theme it your way with a flexible design system.

The key is flex: 1 1 250px. This tells each card: "Start at 250px wide. Grow to fill available space. Shrink if needed." Combined with flex-wrap: wrap, cards that cannot fit on one line wrap to the next. The result is a layout that shows 3 cards on wide screens, 2 on medium screens, and 1 on narrow screens, all without a single media query.

Flexbox vs Grid for cards: Flexbox card layouts are content-driven: cards can have different widths based on their content. CSS Grid card layouts are container-driven: all cards are forced into identical columns. Use Flexbox when you want flexibility, Grid when you want strict uniformity. For most card grids, either works fine.

12. Common Mistakes & Fixes

Mistake 1: Forgetting that Flexbox only affects direct children.
You add display: flex to a parent, but the element you want to align is nested two levels deep. Flexbox does not reach it.
Fix: Either restructure your HTML so the target element is a direct child, or make the intermediate element a flex container too. Flexbox needs to be applied at every level where you want flex behavior.
Mistake 2: Using align-items when you need align-content.
You have a wrapping flex container with multiple rows, and align-items is not spacing the rows the way you expect.
Fix: Use align-content for multi-line containers (when flex-wrap: wrap is set). align-items aligns items within a single line. align-content aligns the lines themselves.
Mistake 3: Expecting justify-content to work vertically in a row layout.
You set justify-content: center expecting vertical centering, but items only center horizontally.
Fix: In a row layout, justify-content controls the horizontal axis. For vertical centering, use align-items: center. Remember: justify = main axis, align = cross axis. If you switch to flex-direction: column, the axes swap.
Mistake 4: Items do not wrap even though there is not enough space.
Items squeeze together or overflow the container instead of moving to a new line.
Fix: Add flex-wrap: wrap to the container. The default is nowrap, which forces all items onto one line no matter what.
Mistake 5: Using width instead of flex-basis.
You set width: 200px on a flex item, but it does not behave the way you expect when the container resizes.
Fix: Use flex-basis (or the flex shorthand) instead of width for flex items. While width often works, flex-basis is the correct property for sizing within a flex context, and it plays better with flex-grow and flex-shrink.
Mistake 6: Vertical centering does not work because the container has no height.
You add align-items: center but nothing changes visually.
Fix: The container needs to be taller than its content for vertical alignment to have an effect. Add height: 100vh, min-height: 100vh, or a specific height value to the container.

13. Next Steps

You now understand the core of CSS Flexbox. You know how to create flex containers, control direction, align and distribute items, handle wrapping, manage spacing, and build real layouts. Here is where to go next to keep building your skills: