skip to content

In a Flexbox nav bar whose children are a logo and several links, how do you push just the last link to the far right while the others stay grouped on the left?

level: middleimportance: should knowfreq 48%

answer

  1. one declaration, no extra wrapper
  2. free space has to go somewhere
  3. auto margin runs before justify-content
  4. space-between spreads every child
  5. logical margin for RTL support

basics

~20 s

Give the last link margin-left: auto. In a flex container an auto margin absorbs all remaining free space in the direction it points, so that item is shoved to the right edge while its siblings stay packed on the left.

solid answer

~40 s

The idiomatic answer is `margin-left: auto` on the item you want pushed — or `margin-inline-start: auto` if the site is bidirectional. In flex layout an `auto` margin soaks up all the free main-axis space before `justify-content` gets to distribute anything, so a single declaration splits the row into a left group and one right-aligned item, with no extra wrapper element. `justify-content: space-between` is the wrong tool once there are more than two children, because it spreads *every* child evenly instead of keeping the logo and links together. The older workaround was an empty spacer element with `flex: 1`; it still works but adds meaningless markup. The same trick generalises: `margin-right: auto` on the logo pushes everything after it to the right, and `margin-left: auto` on two adjacent items creates a three-group bar.

code

css · 9 lines
css
.nav {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav__signout {
  margin-inline-start: auto;
}

go deeper

for a junior

Know the one-liner: margin-left: auto on the item you want pushed to the right edge. Be able to say it works because the auto margin soaks up the leftover space in the row.

for a middle

Explain the ordering rule — auto margins take free space before justify-content distributes it — and why space-between breaks once the bar has more than two children. Mention the logical margin-inline-start form.

for a senior

Show the tradeoffs: no layout-only wrapper elements, what happens when free space runs out at narrow widths, and when a three-column grid is the honest choice over stacked auto margins. Interviewers want to hear you reason about the responsive failure mode.

for a principal

Own the convention across a design system: whether nav composition is expressed by auto margins, by a reusable spacer primitive, or by grid areas, and how that choice holds up under RTL, theming and per-page overrides.

## The free-space rule Everything here follows from one rule in the flex layout algorithm: after flex items are sized, any `auto` margin on the main axis absorbs the remaining free space, and it does so **before** `justify-content` distributes anything. If several margins are `auto`, they share the space equally. Once auto margins have eaten all the free space, `justify-content` has nothing left to position and effectively becomes inert. That single rule is why `margin-left: auto` behaves like "push me and everything after me to the right". ## The recipe ```css .nav { display: flex; align-items: center; gap: 1rem; } .nav__signout { margin-left: auto; } ``` The logo and the ordinary links stay packed at the start; the sign-out link is shoved to the end. No wrapper, no spacer, no change to the markup. If the last two items should travel together as a right-hand group, put the auto margin on the first of the two — the margin only creates one split point. For a bidirectional site, prefer the logical form: `margin-inline-start: auto` follows the writing direction, so the same rule pushes the item to the left edge in an RTL locale instead of stranding it on the physical right. ## Why space-between is not the answer `justify-content: space-between` puts the first item at the start, the last at the end, and equal gaps between everything in between. With exactly two children that produces the desired look by accident. With a logo plus four links plus a button, it spreads all six evenly across the bar, so the "left group" is no longer a group. You can rescue it by wrapping the left-hand items in a single element — then the container really does have two children — but that means adding a `div` purely for layout, which is exactly what the auto margin avoids. ## The spacer variant ```css .nav__spacer { flex: 1; } ``` An empty element with `flex: 1` grows to fill the free space and pushes what follows to the right. This predates widespread understanding of auto margins and still appears in older codebases. It works, but it introduces an element with no meaning that assistive technology must skip over, and it is one more thing to keep in sync when items are added. The auto margin achieves the same layout with zero markup. A related hack is `flex-grow: 1` on the logo itself. It also pushes the rest right, but it does so by inflating the logo's box while the logo's own content stays at the left of that inflated box — the visual result is similar, the mental model is worse, and any background or border on the logo now spans half the bar. ## Building richer bars from the same rule Because each auto margin creates one split point, you can compose them: ```css .nav__center { margin-left: auto; } .nav__actions { margin-left: auto; } ``` With those two declarations the free space is shared equally between the two auto margins, so you get three visually separated groups — start, centre-ish, end — from a flat list of items. It is not a true centre (the middle group is only centred when the two side groups are the same width), and when true centering matters a three-column grid is the honest tool. ## Cross-axis auto margins The rule is not main-axis-only. In a row container, `margin-top: auto` on one item pushes it to the bottom of the line, and `margin-bottom: auto` pushes it to the top — a compact way to bottom-align a single badge in an otherwise centred bar without touching `align-items` for everyone. ## Gotchas An auto margin only absorbs space that is actually free. If the items already fill or overflow the container, there is nothing to absorb and the item does not move — the layout looks broken until the viewport widens, which is the usual cause of "my auto margin stopped working". Similarly, combining `justify-content: center` with an auto margin is a contradiction in practice: the margin takes the free space first, so the centering silently does nothing. Pick one mechanism and stay with it. Finally, remember `gap` still applies around the pushed item, so the visual distance from its neighbour is the gap plus whatever free space the margin absorbed — usually irrelevant, occasionally the reason a bar looks a few pixels off from a design.

  • What happens if you set both an auto margin and justify-content: center on the same container?
    The auto margin wins in practice. Auto margins absorb the free main-axis space before `justify-content` distributes anything, so by the time centering is applied there is no space left to distribute and it has no visible effect. Mixing the two is a common source of "justify-content does nothing" confusion — choose one mechanism.
  • How do you get three groups — left, centre, right — from a flat list of flex children?
    Put `margin-left: auto` on the first item of the middle group and on the first item of the right group; the two auto margins share the free space equally. It only looks truly centred when the left and right groups are the same width, so when exact centering matters use a three-column grid instead.
  • Why does the auto margin sometimes appear to stop working on narrow screens?
    Because it can only absorb space that is free. Once the items fill or overflow the container there is no leftover space, so the item stays put next to its neighbour. That is a sign the bar needs to wrap, collapse into a menu, or let some item shrink at that breakpoint.

saying these in an interview costs you the question

  • Using justify-content: space-between with more than two children
  • Adding an empty spacer div when a margin would do
  • Thinking margin-left: auto adds a fixed default gap
  • Applying flex-grow to the logo to fake the push
  • Assuming physical margin-left is correct in RTL layouts

context