Flexbox
By default blocks go one under another. Flexbox (the flexible layout) lines them up in a row or a column and controls alignment and free space. It is the main tool for headers, menus, button bars and cards.
Container and items
Flexbox is turned on at the parent with display: flex. The parent becomes a flex container, and its direct children become flex items and line up in a row:
<style>
.row { display: flex; }
.row div { padding: 12px; background: lavender; border: 1px solid mediumpurple; }
</style>
<div class="row">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>The items became as wide as their content and lined up from left to right.
Direction
The direction in which the items go is called the main axis. The perpendicular one is the cross axis. The flex-direction property changes the main axis: row is a row (the default), column is a column:
<style>
.col { display: flex; flex-direction: column; }
.col div { padding: 8px; background: honeydew; border: 1px solid seagreen; }
</style>
<div class="col">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>Gaps
gap sets the distance between the items. The items need no margins of their own, and no extra space appears outside the outer items:
<style>
.row { display: flex; gap: 16px; }
.row div { padding: 12px; background: lavender; }
</style>
<div class="row">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>Alignment along the main axis
justify-content distributes the free space along the main axis:
| Value | Result |
|---|---|
flex-start | Items pressed to the start (the default) |
center | In the center |
flex-end | Pressed to the end |
space-between | The outer ones at the edges, the rest of the space shared equally between items |
<style>
.row { display: flex; gap: 8px; margin-bottom: 8px; background: whitesmoke; }
.row div { padding: 8px 12px; background: lightskyblue; }
.center { justify-content: center; }
.between { justify-content: space-between; }
.end { justify-content: flex-end; }
</style>
<div class="row center"><div>A</div><div>B</div></div>
<div class="row between"><div>A</div><div>B</div></div>
<div class="row end"><div>A</div><div>B</div></div>Alignment across
align-items aligns the items along the cross axis — in a row that is the height of the container. Together with justify-content: center it puts an item exactly in the center of the block:
<style>
.stage {
display: flex;
justify-content: center;
align-items: center;
height: 120px;
background: whitesmoke;
}
.stage div { padding: 12px; background: gold; }
</style>
<div class="stage"><div>Centered</div></div>By default align-items is stretch: the items stretch to the full height of the row.
Wrapping
When the items do not fit, flexbox squeezes them into one line. flex-wrap: wrap lets them move to a new line:
<style>
.tags { display: flex; flex-wrap: wrap; gap: 8px; }
.tags span { padding: 4px 12px; border-radius: 999px; background: honeydew; border: 1px solid seagreen; }
</style>
<div class="tags">
<span>HTML</span><span>CSS</span><span>JavaScript</span><span>Python</span>
<span>TypeScript</span><span>PHP</span><span>SQL</span><span>Rust</span>
<span>Kotlin</span><span>Swift</span><span>Go</span><span>Ruby</span>
</div>Common mistake
display: flex affects only the direct children of the container. If the items are wrapped in one more block, that block lines up in the row, not the items:
<style>
.wrong { display: flex; gap: 8px; }
.wrong span { padding: 8px; background: mistyrose; }
</style>
<div class="wrong">
<div>
<span>First</span>
<span>Second</span>
</div>
<span>Third</span>
</div>The first two items stayed inside the wrapper and did not get the gap. Turn flexbox on at the block whose children should line up.