Skip to main content
Back to module
HTML & CSS Foundations · CSS Layout & Style

Flexbox tour

Reading1h 13mLesson 2 of 4 in this module

What you'll learn

  • Lay out a nav bar and cards with flexbox
  • Explain the main axis and cross axis and which property aligns along each
  • Space flex items with gap instead of margins
  • Make a card row wrap responsively with flex-wrap and the flex shorthand

Lay out a navigation bar and a row of cards with Flexbox: direction, alignment, gap and wrapping.

Why this matters

Before Flexbox, putting three boxes side by side and centring them vertically took floats, clearfix hacks and guesswork. Flexbox makes one-dimensional layout (a row or a column of items) simple and predictable. Navigation bars, toolbars, card rows, button groups and "centre this thing" are all Flexbox jobs you will meet every week.

The core idea: a container and its items

You turn an element into a flex container with one declaration. Its direct children become flex items:

CSS
.nav-list {
  display: flex;
}
HTML
<ul class="nav-list">
  <li><a href="#routes">Routes</a></li>
  <li><a href="#events">Events</a></li>
  <li><a href="#join">Join</a></li>
</ul>

The three list items now sit in a row. Only the direct children are affected; the links inside the items are laid out normally.

Two axes

A flex container has a main axis and a cross axis.

  • flex-direction: row (the default) makes the main axis horizontal.
  • flex-direction: column makes the main axis vertical.

Alignment properties are named after the axes, not after left/right or top/bottom, which is why they swap meaning when you change direction:

PropertySet onWorks alongCommon values
justify-contentcontainermain axisflex-start, center, space-between, flex-end
align-itemscontainercross axisstretch (default), center, flex-start, flex-end
gapcontainerbetween items1rem, 0.5rem 1rem
flex-wrapcontainerlinesnowrap (default), wrap

Worked example 1: a header bar

Logo on the left, navigation on the right, both centred vertically:

CSS
.site-header {
  display: flex;
  justify-content: space-between;  /* push the two children apart */
  align-items: center;             /* centre them vertically */
}

.nav-list {
  display: flex;
  gap: 1rem;            /* space between links, none at the ends */
  list-style: none;     /* remove the bullets */
  margin: 0;
  padding: 0;
}

Flexbox containers can be nested: the header is a flex container whose second child (the nav's list) is a flex container itself.

gap is the modern way to space items. It puts space only between items, so you no longer need margins that leave an awkward extra gap at the end.

Worked example 2: cards that wrap

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

.card {
  flex: 1 1 200px;
}

flex: 1 1 200px is shorthand for three item properties:

  • flex-grow: 1: if there is spare space, take a share of it.
  • flex-shrink: 1: if space is tight, you may shrink.
  • flex-basis: 200px: start from a width of about 200px before growing or shrinking.

With flex-wrap: wrap, cards that do not fit move to the next line, and each line's cards grow to fill it. On a wide screen you get three cards in a row; on a phone, one per row. No media query needed.

Centring anything

The classic "centre a box both ways" problem becomes:

CSS
.hero {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 60vh;
}

Ordering, and why to be careful

order and flex-direction: row-reverse change the visual order without changing the HTML. Keyboard focus and screen readers still follow the HTML order, so a visual order that differs from the source confuses keyboard users. Change the HTML order instead whenever you can.

Common mistakes

  • Putting display: flex on the item instead of the parent.
  • Expecting grandchildren to be flex items. Only direct children are.
  • Mixing up the axes after switching to flex-direction: column (now justify-content is vertical).
  • Forgetting flex-wrap: wrap, so items squash or overflow instead of wrapping.
  • Using margins for spacing where gap would be simpler.

Quick recap

  • display: flex on the parent; direct children become flex items.
  • justify-content aligns along the main axis, align-items across it; gap spaces items.
  • flex-wrap: wrap plus flex: 1 1 <basis> gives responsive card rows.
  • Keep the HTML order and the visual order the same.

Try it

Open the Do tab and use Flexbox to turn a stacked header and cards into a proper nav bar and a wrapping card row.

Key terms (5)

flex container
An element with display: flex; its direct children are laid out as flex items in a row or column.
main axis
The direction flex items flow in, horizontal for row and vertical for column, along which justify-content aligns.
cross axis
The axis at right angles to the main axis, along which align-items aligns flex items.
gap
A container property that adds space only between items, never at the ends.
flex-basis
The starting size of a flex item before it grows or shrinks to share the available space.

Recap

  • display: flex goes on the parent; only its direct children become flex items.
  • justify-content aligns along the main axis and align-items across it; switching to column swaps them.
  • gap spaces items without extra space at the ends.
  • flex-wrap: wrap plus a flex basis gives a card row that adapts with no media query.
  • Keep the visual order the same as the HTML order.
Also in this lesson: