Aligning with Flexbox
A flex container has two axes. The main axis runs in the flex-direction, left to right for a row. The cross axis runs across it.
justify-contentaligns items along the main axis.align-itemsaligns them along the cross axis.
Try them
<style>
body { font-family: system-ui; }
.controls { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 10px; font-size: 14px; }
.box { display: flex; height: 160px; gap: 8px; padding: 8px; border: 2px dashed #b7adff; border-radius: 10px; background: #f4f2ff; }
.box div { padding: 8px 12px; border-radius: 6px; background: #5a48f5; color: white; }
.box div:nth-child(2) { padding: 22px 12px; }
code { display: inline-block; margin-top: 8px; padding: 6px 10px; border-radius: 6px; background: #11151f; color: #e9ecf5; font-size: 13px; }
</style>
<div class="controls">
<label>justify-content
<select id="jc">
<option>flex-start</option><option>center</option><option>flex-end</option>
<option>space-between</option><option>space-around</option><option>space-evenly</option>
</select>
</label>
<label>align-items
<select id="ai">
<option>stretch</option><option>flex-start</option><option>center</option>
<option>flex-end</option><option>baseline</option>
</select>
</label>
<label>flex-direction
<select id="fd"><option>row</option><option>column</option></select>
</label>
</div>
<div class="box" id="box"><div>One</div><div>Two</div><div>Three</div></div>
<code id="css"></code>
<script>
const box = document.querySelector("#box");
const pick = (id) => document.querySelector(id).value;
function update() {
box.style.justifyContent = pick("#jc");
box.style.alignItems = pick("#ai");
box.style.flexDirection = pick("#fd");
document.querySelector("#css").textContent =
`flex-direction: ${pick("#fd")}; justify-content: ${pick("#jc")}; align-items: ${pick("#ai")};`;
}
document.querySelectorAll("select").forEach((s) => s.addEventListener("change", update));
update();
</script>Switch flex-direction to column, and the two properties swap roles: justify-content now works vertically and align-items horizontally.
The values
justify-content | Effect |
|---|---|
flex-start | packed at the start (the default) |
center | packed in the middle |
flex-end | packed at the end |
space-between | first and last items at the edges, equal gaps between |
space-around | equal space around each item, so the edge gaps are half-size |
space-evenly | exactly equal gaps everywhere, edges included |
align-items | Effect |
|---|---|
stretch | items stretch to fill the cross axis (the default) |
flex-start, flex-end | to the top or bottom, in a row |
center | centred across |
baseline | the first lines of text line up |
Centring anything
<style>
.stage { display: flex; justify-content: center; align-items: center; height: 180px; border-radius: 12px; background: #11151f; }
.dialog { padding: 18px 22px; border-radius: 10px; background: white; font: 15px system-ui; }
</style>
<div class="stage"><div class="dialog">Perfectly centred</div></div>Two lines centre anything in both directions, a job that once took clever tricks. Grid does it in one: display: grid; place-items: center.
One item differently: align-self
<style>
.row { display: flex; align-items: flex-start; gap: 8px; height: 130px; padding: 8px; border-radius: 10px; background: #f4f2ff; font: 14px system-ui; }
.row div { padding: 10px; border-radius: 6px; background: #0aa9cf; color: white; }
.row .down { align-self: flex-end; background: #e0663a; }
</style>
<div class="row"><div>start</div><div class="down">align-self: flex-end</div><div>start</div></div>align-self overrides align-items for a single item.
Auto margins push items apart
<style>
.bar { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-radius: 10px; background: #11151f; font: 14px system-ui; }
.bar span { color: #e9ecf5; }
.bar .push { margin-left: auto; }
.bar button { padding: 8px 14px; border: 0; border-radius: 6px; background: #5a48f5; color: white; }
</style>
<div class="bar">
<span>☰</span><span>Dashboard</span>
<span class="push">Asha</span><button>Sign out</button>
</div>An auto margin soaks up all the free space on its side, so margin-left: auto shoves its item, and everything after it, to the far end.
Changing the visual order
<style>
.row { display: flex; gap: 8px; font: 14px system-ui; }
.row div { padding: 10px 14px; border-radius: 6px; background: #eef0ff; }
.row .first { order: -1; background: #d9f7ea; }
</style>
<div class="row"><div>1</div><div>2</div><div class="first">3, with order: -1</div></div>order changes where an item is drawn (the default is 0, and lower numbers come first), but not its place in the HTML. Screen readers and the Tab key still follow the HTML, so don't use order where the sequence carries meaning.
Wrapped lines: align-content
When items wrap onto several lines, align-content spaces out the lines along the cross axis. It takes the same values as justify-content, and does nothing when there's only one line.