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.
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-contentworks along the main axis (horizontal in a row).align-itemsworks 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-endpacks them at the end.centerputs them in the middle.space-betweenputs the first item at the start, the last at the end, and splits the rest evenly. It is perfect for navbars.space-aroundgives each item equal space around itself, so the gaps at the edges are half the gaps between items.space-evenlymakes 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-contentoralign-itemson the items instead of the container. (align-selfis the only one that goes on an item.) - Trying
align-items: centeron a container with no extra height. There is no space to centre in. Give it aheightormin-height. - Forgetting that the axes swap in a column.
justify-contentis then vertical. - Expecting
align-items: stretchto work on an item that has a fixedheight. - Using
justify-contentand expecting an effect when there is no free space, for instance when the items already fill the row. - Leaving
flex-wrapoff and being puzzled that the items squash or overflow. - Confusing
align-itemsandalign-content.align-itemspositions items within a line,align-contentpositions the lines of a wrapped container. - Using margins instead of
gapfor spacing between wrapped rows.
Practice
- Click Practice in Editor. Try every value of
justify-contenton.demo-justify. Which one would you use for a navbar? - On
.demo-align, tryflex-start,flex-end,center,stretchandbaseline. Which items change, and which ones do not? - Add
align-selfto the second item in Part 3 so that it sits at the bottom while the others stay at the top. - Turn
.demo-columninto a column, give it a height, and spread its items evenly withjustify-content: space-evenly. Then tryalign-items: flex-end. - 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 toflex: 1 1 120px. - Centre a single box in the middle of the preview using the three-line recipe.
- Build a row with a heading on the left and a button on the far right, using only
margin-left: auto.
Recap
justify-contentpositions items along the main axis:flex-start,flex-end,center,space-between,space-around,space-evenly.align-itemspositions them along the cross axis:stretch(default),flex-start,flex-end,center,baseline.align-selfoverrides it for one item.- In a
columncontainer, the two properties swap directions, and the container needs a height. margin: autoon a flex item absorbs free space, which is ideal for pushing items apart.flex-wrap: wraplets items flow onto more lines.align-contentpositions 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.