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

Flexbox tour

Reading1h 13mLesson 2 of 4 in this module

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:

.nav-list {
  display: flex;
}
<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:

.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

.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:

.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.

Also in this lesson: