To push some flex items apart, you do not need a spacer element. Flexbox has three native tools, and which one you reach for depends on the layout:
- One item to the far end (logo left, account menu right): put
margin-left: autoon the item you want pushed. - Items spread to both edges with the gap in the middle:
justify-content: space-betweenon the container. - Even, fixed spacing between every item:
gapon the container.
That covers almost every real case. The empty <div class="spacer"> you may have seen in older tutorials is not one of them, and I will get to why.
Push one item to the far end with margin-auto
This is the cleanest answer to "send this one item to the right." A flex item with margin-left: auto absorbs all the free space on its left, so it and everything after it slide to the end of the row. The classic example is a navbar: brand on the left, the rest of the links flowing after it, and an account menu pinned to the right edge.
.nav {
display: flex;
align-items: center;
gap: 1rem;
}
/* Everything before this stays left; this and anything after it go right. */
.nav .account {
margin-left: auto;
}<nav class="nav">
<a class="brand" href="/">TechEarl</a>
<a href="/blog">Blog</a>
<a href="/about">About</a>
<a class="account" href="/account">Account</a>
</nav>An auto margin is greedy: it eats every pixel of free space in its direction. That is exactly the behavior you want here, and it is the idiomatic toolbar pattern. One important interaction to know: auto margins are resolved before justify-content, so once any item in the row has an auto margin, justify-content has nothing left to distribute and stops mattering. Pick one mechanism per axis, not both.
You can also split a row into two groups (left cluster, right cluster) by putting margin-left: auto on the first item of the right-hand group, no wrapper needed.
Spread items to the edges with space-between
When you want the first item flush left, the last item flush right, and the leftover space dropped evenly between the items, set it on the container:
.bar {
display: flex;
justify-content: space-between;
align-items: center;
}The two siblings of space-between are worth knowing:
/* space-around: equal space around each item, so half-size gaps at the two ends. */
.a { justify-content: space-around; }
/* space-evenly: truly equal space everywhere, including the two ends. */
.b { justify-content: space-evenly; }space-between is the one you want for a two-item header (logo left, button right) or a row of tabs that should fill the width. Reach for margin-auto instead when only a single item needs to break ranks while the others stay grouped, since space-between distributes the gap across all the items, not just one seam.
Even spacing between items with gap
If the goal is just consistent breathing room between items (a row of buttons, nav links that should sit a fixed distance apart), gap is the right tool. It is the flexbox property people forget exists, and it has been safe to use across all browsers since 2021.
.toolbar {
display: flex;
gap: 0.75rem; /* space between items, none on the outer edges */
}
/* Different row and column gaps if the items wrap: */
.grid-ish {
display: flex;
flex-wrap: wrap;
gap: 1rem 1.5rem; /* row-gap column-gap */
}gap only adds space between items, never before the first or after the last, which is usually what you want and what manual margins on every child get wrong (you end up fighting a trailing margin with :last-child). It also composes cleanly with margin-left: auto: use gap for the uniform spacing and one auto margin for the item that breaks to the far edge.
The thing not to do: an empty spacer div
The pattern to retire is the empty filler element:
<!-- Don't do this. -->
<nav class="nav">
<a href="/">TechEarl</a>
<div class="spacer"></div>
<a href="/account">Account</a>
</nav>/* Don't do this either. */
.spacer { flex-grow: 1; }It works, visually. But it adds a non-semantic, empty element to the DOM purely to occupy space, which is exactly the job CSS is supposed to do. A screen reader has nothing to read there, it clutters the markup, and the moment your links change you are maintaining a phantom div. The single line margin-left: auto on the .account link does the same thing with no extra element, so use that. If you genuinely need a spacer with no markup at all, a ::before/::after pseudo-element with flex-grow: 1 is the honest version, but in practice margin-auto and space-between cover it.
For the rest of flexbox (axes, wrapping, alignment, flex-grow/flex-shrink/flex-basis), see my complete flexbox guide. If your goal is dead-centering rather than pushing apart, centering anything in CSS walks through the flexbox, grid, and margin-auto routes. And once you are styling based on what a container holds (a nav that has an active link, say), the CSS :has() selector is the modern companion to these layout tools.
FAQ
See also
- The complete flexbox guide: axes, wrapping, alignment, and the flex-grow/shrink/basis shorthand in full.
- Center anything in CSS: the flexbox, grid, and margin-auto routes to dead-centering, the opposite problem to pushing apart.
- The CSS :has() parent selector: style a container based on what it holds, the modern companion to these layout tools.
Sources
Authoritative references this article was fact-checked against.
- justify-content (MDN, official)developer.mozilla.org
- Aligning items in a flex container (MDN, official)developer.mozilla.org
- margin (MDN, official)developer.mozilla.org





