CSSIntermediate

Flexbox Alignment and Wrapping: justify-content, align-items

Control where flex items sit with justify-content, align-items and align-self, let them wrap onto new lines, and center anything with a few lines of CSS.

All CSS lessons

What you will learn

In the last lesson you made items sit in a row or a column and share space. Now for the part everyone loves about Flexbox: alignment. You will learn how to push items to the start, the end or the middle, how to spread them out evenly, how to line them up on the cross axis, and how to let them wrap onto new lines when there is not enough room. You will finish with the shortest way to centre anything on a page.

The HTML we will style

The practice page has five containers, one for each idea:

<h1 class="page-title">Flexbox Alignment Lab</h1>

<!-- Part 1: justify-content (main axis) -->
<div class="demo demo-justify">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>

<!-- Part 2: align-items (cross axis) -->
<div class="demo demo-align">
  <div class="item">1 (no height)</div>
  <div class="item item-medium">2 (60px)</div>
  <div class="item item-large">3 (90px)</div>
</div>

<!-- Part 3: align-self (one item breaks the rule) -->
<div class="demo demo-self">
  <div class="item">1</div>
  <div class="item item-self">2 (align-self)</div>
  <div class="item">3</div>
</div>

<!-- Part 4: a column container -->
<div class="demo demo-column">
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>

<!-- Part 5: wrapping onto several lines -->
<div class="demo demo-wrap">
  <div class="tile">1</div>
  <!-- ... tiles 2 to 8 ... -->
</div>
Selector Element Role
.demo all five container <div>s flex containers (shared look: display: flex, gap, padding, grey background)
.demo-justify Part 1 container tries out justify-content
.demo-align Part 2 container tries out align-items (it has a fixed height)
.demo-self Part 3 container tries out align-self
.demo-column Part 4 container a vertical flex container
.demo-wrap Part 5 container tries out flex-wrap
.item the blue boxes in Parts 1 to 4 flex items
.item-medium, .item-large the 2nd and 3rd item in Part 2 items with their own heights
.item-self the 2nd item in Part 3 the item that overrides the container
.tile the eight boxes in Part 5 flex items that will wrap

Remember the axes

These properties are described by the axes, so keep this picture in mind:

  • justify-content works along the main axis (horizontal in a row).
  • align-items works along the cross axis (vertical in a row).

If you switch to flex-direction: column, the two swap jobs: justify-content now works vertically and align-items horizontally.

justify-content: along the main axis

justify-content decides what to do with leftover space along the main axis. It goes on the container:

/* the <div class="demo demo-justify"> */
.demo-justify {
  justify-content: center;
}

Here are the six values, drawn for a row of three items (the vertical bars are the container’s edges):

flex-start     |[1][2][3]                                   |
flex-end       |                                   [1][2][3]|
center         |                 [1][2][3]                  |
space-between  |[1]                 [2]                  [3]|
space-around   |      [1]            [2]           [3]      |
space-evenly   |         [1]         [2]        [3]         |
  • flex-start (default) packs items at the start.
  • flex-end packs them at the end.
  • center puts them in the middle.
  • space-between puts the first item at the start, the last at the end, and splits the rest evenly. It is perfect for navbars.
  • space-around gives each item equal space around itself, so the gaps at the edges are half the gaps between items.
  • space-evenly makes all gaps equal, including the edges.

justify-content only has an effect when there is free space. If the items already fill the container, there is nothing to distribute.

align-items: along the cross axis

align-items decides how items line up across the main axis. In a row that means vertically, so the container needs some extra height to make the effect visible (that is why .demo-align has height: 140px).

/* the <div class="demo demo-align"> */
.demo-align {
  height: 140px;
  align-items: center;
}
Value Result
stretch the default: items stretch to fill the container’s height, if they have no height of their own
flex-start items sit at the top
flex-end items sit at the bottom
center items are centred vertically
baseline items line up along the first line of their text

Why did the first item look taller than its content before you added align-items? Because of stretch: it has no height, so it stretches to the container. The other two have a height, which stops them from stretching. Set align-items: flex-start and the first item shrinks back to its content.

align-self: one item breaks the rule

align-items is set on the container and applies to every item. align-self is set on one item and overrides it:

/* the container: all items at the top */
.demo-self {
  height: 120px;
  align-items: flex-start;
}

/* the <div class="item item-self">: this one goes to the bottom */
.item-self {
  align-self: flex-end;
}

align-self accepts the same values as align-items (plus auto, which means “follow the container”).

Auto margins: a handy trick

In a flex container, an auto margin soaks up all the free space on that side, which pushes the item away from its neighbours:

/* the <div class="item item-self"> in Part 3 */
.item-self {
  margin-left: auto;   /* pushes this item (and everything after it) to the far end */
}

This is the cleanest way to put a logo on the left and a login button on the right, and you will use it in the next lesson. margin: auto on a flex item even centres it both ways.

Direction changes everything: a column container

Now turn the container into a column:

/* the <div class="demo demo-column"> */
.demo-column {
  flex-direction: column;
  height: 220px;
  justify-content: space-between;   /* now VERTICAL */
  align-items: center;              /* now HORIZONTAL */
}

The main axis is vertical, so justify-content: space-between spreads the three items from top to bottom, and align-items: center centres them horizontally. The container needs a height, otherwise there is no free vertical space to distribute.

Wrapping: flex-wrap

By default, a flex container keeps everything on one line (flex-wrap: nowrap). If the items are too wide, they shrink, and if they cannot shrink they overflow. To let them flow onto a second line instead, use flex-wrap:

/* the <div class="demo demo-wrap"> */
.demo-wrap {
  flex-wrap: wrap;
}

/* the eight <div class="tile"> boxes */
.tile {
  flex: 0 0 120px;      /* always 120px wide: never shrink */
  height: 60px;
  background-color: seagreen;
  color: white;
  padding: 10px;
}
Value Result
nowrap the default: single line, items shrink or overflow
wrap items move to a new line when they run out of room
wrap-reverse wrap, with the new lines added above instead of below

Without wrap, the tiles would either be squashed or run out of the container. With it, they flow into rows like words in a paragraph: as many 120px tiles as fit on a line, then the next line begins. The gap property applies between rows as well as between columns, so the rows are neatly spaced.

You can combine the direction and wrapping into one line using the shorthand flex-flow: row wrap;.

Making wrapped items fill each line

To get tiles that grow to fill each row (so there are no ragged gaps), let them grow from a minimum size:

.tile {
  flex: 1 1 120px;     /* start at 120px, then share the leftover space */
}

Now each line is completely filled. The last row can have fewer tiles that are wider than the others. If you want every tile to stay the same width as the rows above, CSS Grid is a better tool. It is the topic of the Grid lesson.

align-content: aligning the lines themselves

When items wrap onto several lines, align-items positions the items inside each line, and align-content positions the lines themselves inside the container. It only has an effect when the container has extra height and more than one line:

.demo-wrap {
  flex-wrap: wrap;
  height: 300px;
  align-content: flex-start;   /* pack the lines at the top (try center, space-between) */
}

It uses the same family of values as justify-content: flex-start, center, space-between, space-around, space-evenly, and the default stretch.

The famous centring recipe

Centering something both horizontally and vertically used to be a notorious problem. With Flexbox, it is three lines on the parent:

.center-me {
  display: flex;
  justify-content: center;    /* centre along the main axis (horizontal) */
  align-items: center;        /* centre along the cross axis (vertical) */
  min-height: 100vh;          /* give it some height to centre in */
}

Whatever is inside is now perfectly centred, whatever its size. (place-items: center on a Grid container achieves the same in one line, as you will see later.)

Putting it together

*, *::before, *::after { box-sizing: border-box; }

.demo {
  display: flex;
  gap: 10px;
  padding: 10px;
  margin-bottom: 20px;
  background-color: #eeeeee;
}

.item {
  width: 90px;
  padding: 10px;
  background-color: royalblue;
  color: white;
}

.item-medium { height: 60px; }
.item-large  { height: 90px; }

.demo-justify {
  justify-content: space-between;
}

.demo-align {
  height: 140px;
  align-items: center;
}

.demo-self {
  height: 120px;
  align-items: flex-start;
}

.item-self {
  align-self: flex-end;
}

.demo-column {
  flex-direction: column;
  height: 220px;
  justify-content: space-between;
  align-items: center;
}

.demo-wrap {
  flex-wrap: wrap;
}

.tile {
  flex: 1 1 120px;
  height: 60px;
  padding: 10px;
  background-color: seagreen;
  color: white;
}

Common mistakes

  • Using justify-content or align-items on the items instead of the container. (align-self is the only one that goes on an item.)
  • Trying align-items: center on a container with no extra height. There is no space to centre in. Give it a height or min-height.
  • Forgetting that the axes swap in a column. justify-content is then vertical.
  • Expecting align-items: stretch to work on an item that has a fixed height.
  • Using justify-content and expecting an effect when there is no free space, for instance when the items already fill the row.
  • Leaving flex-wrap off and being puzzled that the items squash or overflow.
  • Confusing align-items and align-content. align-items positions items within a line, align-content positions the lines of a wrapped container.
  • Using margins instead of gap for spacing between wrapped rows.

Practice

  1. Click Practice in Editor. Try every value of justify-content on .demo-justify. Which one would you use for a navbar?
  2. On .demo-align, try flex-start, flex-end, center, stretch and baseline. Which items change, and which ones do not?
  3. Add align-self to the second item in Part 3 so that it sits at the bottom while the others stay at the top.
  4. Turn .demo-column into a column, give it a height, and spread its items evenly with justify-content: space-evenly. Then try align-items: flex-end.
  5. Make the tiles wrap with flex-wrap: wrap. Resize the preview to see how many tiles fit on each line. Then change the tile rule to flex: 1 1 120px.
  6. Centre a single box in the middle of the preview using the three-line recipe.
  7. Build a row with a heading on the left and a button on the far right, using only margin-left: auto.

Recap

  • justify-content positions items along the main axis: flex-start, flex-end, center, space-between, space-around, space-evenly.
  • align-items positions them along the cross axis: stretch (default), flex-start, flex-end, center, baseline. align-self overrides it for one item.
  • In a column container, the two properties swap directions, and the container needs a height.
  • margin: auto on a flex item absorbs free space, which is ideal for pushing items apart.
  • flex-wrap: wrap lets items flow onto more lines. align-content positions the lines themselves.
  • Centre anything with display: flex; justify-content: center; align-items: center; on its parent.
  • Next you will use Flexbox to build real components: a navbar, cards and more.