Two axes, two properties
Flexbox alignment confuses people until they see one rule. There are exactly two directions, and each has its own property:
justify-contentplaces items along the main axis.align-itemsplaces items along the cross axis.
In the default row direction, the main axis is horizontal and the cross axis vertical. If you switch to flex-direction: column, the axes swap: justify-content now works vertically and align-items horizontally. Whenever alignment seems "backwards", check the direction.
justify-content: along the main axis
<style>
.row { display: flex; gap: 6px; background: #f1f5f9; padding: 8px; margin-bottom: 10px; }
.row div { background: #6366f1; color: white; padding: 8px 14px; border-radius: 6px; }
.start { justify-content: flex-start; }
.center { justify-content: center; }
.end { justify-content: flex-end; }
.between { justify-content: space-between; }
.evenly { justify-content: space-evenly; }
</style>
<div class="row start"><div>A</div><div>B</div><div>C</div></div>
<div class="row center"><div>A</div><div>B</div><div>C</div></div>
<div class="row end"><div>A</div><div>B</div><div>C</div></div>
<div class="row between"><div>A</div><div>B</div><div>C</div></div>
<div class="row evenly"><div>A</div><div>B</div><div>C</div></div>flex-start(default),center,flex-end: pack the items together at one place.space-between: first and last touch the edges, spare space goes between items.space-around: equal space around each item (so edges get half as much).space-evenly: the same space between items and at both edges.
align-items: along the cross axis
<style>
.row { display: flex; gap: 6px; height: 90px; background: #f1f5f9; margin-bottom: 8px; }
.row div { background: #10b981; color: white; padding: 8px 14px; border-radius: 6px; }
.s { align-items: flex-start; }
.c { align-items: center; }
.e { align-items: flex-end; }
.st { align-items: stretch; }
</style>
<div class="row s"><div>start</div><div>B<br>two lines</div></div>
<div class="row c"><div>center</div><div>B<br>two lines</div></div>
<div class="row e"><div>end</div><div>B<br>two lines</div></div>
<div class="row st"><div>stretch (default)</div><div>B<br>two lines</div></div>The default, stretch, is why flex items in a row end up the same height: they fill the cross axis. align-items: baseline lines up the first line of text in each item, which is neat for mixed font sizes.
The famous centring recipe
Centring something both horizontally and vertically used to be a notorious puzzle. With Flexbox it is three lines:
<style>
.stage { display: flex; justify-content: center; align-items: center; height: 160px; background: #fef3c7; }
.box { background: #f59e0b; color: white; padding: 16px 24px; border-radius: 8px; }
</style>
<div class="stage"><div class="box">Perfectly centred</div></div>Give the container a height (or let the page provide one, for example min-height: 100dvh for a full-screen hero), then justify-content: center handles the main axis and align-items: center the cross axis. There is a shorter place-content: center for Grid, which the next lesson covers.
align-self: one item differs
align-self overrides align-items for a single item, using the same values:
.row { display: flex; align-items: flex-start; }
.row .special { align-self: flex-end; }align-content: several lines
If flex-wrap produces more than one line, align-content distributes the lines along the cross axis, using values like flex-start, center and space-between. It has no effect on a single line (use align-items there), and it needs extra height to work with.
Alignment with auto margins
An auto margin on a flex item absorbs spare space on that side, overriding justify-content. That is how a logo gets pushed left and links right, as in the last lesson. It is a precise way to separate one item from the rest.
Reading direction
flex-start and flex-end follow the writing direction, not "left" and "right". In a right-to-left language the row starts on the right. That is the correct behaviour, and why these names are better than left and right.
Common mistakes
- Using
justify-contentfor vertical centring in a row. Usealign-items. - A container with no height, so vertical centring seems to do nothing.
- Forgetting that switching to column swaps the roles.
- Using
text-align: centerfor the box instead of flex alignment (it only centres inline content). - Expecting
align-contentto work on a single line.
Exercise
Create a header bar with a logo on the left, a menu in the middle that is centred, and a button on the right, all vertically centred in a 64px-high bar.
Show one possible answer
<style>
.bar { display: flex; align-items: center; justify-content: space-between; height: 64px; padding: 0 16px; background: #0f172a; color: white; }
.bar nav { display: flex; gap: 16px; }
.bar button { padding: 8px 16px; border: 0; border-radius: 999px; }
</style>
<header class="bar">
<strong>Logo</strong>
<nav><a href="#">Home</a><a href="#">Courses</a><a href="#">Blog</a></nav>
<button>Sign in</button>
</header>With space-between and three items, the middle one lands in the centre only if the side items are equally wide. For exact centring, use Grid with three equal columns.
Key points
- justify-content positions items along the main axis, and align-items positions them along the cross axis.
- Centring both ways takes just three lines with display flex, justify-content center and align-items center.
- align-self overrides align-items for a single item.
- space-between, space-around and space-evenly distribute spare room in different ways.
- When flex-direction changes to column, the roles of justify-content and align-items swap with the axes.