What is the difference between justify-content and align-items?

Beginner8 min interview
Skills tested:
Mapping each property to its axisExplaining that justify-content distributes free space while align-items positions within the lineKnowing which values are unique to each propertyExplaining why align-items defaults to stretchRecognising that justify-content needs free space to have any effect

Advertisement

🧩 Scenario

These two properties account for most of the Flexbox you will ever write: a navbar with a logo on the left and links on the right is justify-content: space-between plus align-items: center, and that pattern repeats in headers, toolbars, cards, and list rows across every product. Knowing precisely which one does what avoids the trial-and-error cycle of swapping them until the layout looks right.

Architecture Walkthrough

Different Axes, Different Jobs

justify-content operates on the main axis, the direction set by flex-direction. align-items operates on the cross axis, always perpendicular to it. In the default flex-direction: row, that means justify-content works horizontally and align-items works vertically; in column, the two swap.

Beyond the axis, they do genuinely different jobs.

justify-content distributes free space along the main axis. It answers: given leftover room after the items are sized, where does that room go? Before it, after it, between items, or spread evenly? Because it operates on free space, it has no effect at all when the items already consume the full main-axis size, which is one of the two common reasons it appears to do nothing.

align-items positions each item within the line's cross-axis extent. It answers: given that the line is a certain thickness, where does each item sit within it? Top, bottom, centre, on the text baseline, or stretched to fill?

Value Sets Differ, and the Differences Are Meaningful

The two properties share flex-start, flex-end, and center, but their remaining values reveal what each one is for.

Only justify-content has the distribution values space-between, space-around, and space-evenly, because only it deals with free space to distribute. space-between puts the first item at the start, the last at the end, and splits the remainder equally between them. space-around gives each item equal space on both sides, so the outer gaps look half the size of the inner ones. space-evenly makes every gap identical, including the outer ones.

Only align-items has stretch and baseline. stretch is its default value and is the reason flex children fill their container's cross axis without being asked, which is where equal-height columns come from for free. baseline aligns items by the baseline of their first line of text, which matters when items have different font sizes and you want their text to sit on a shared line rather than their boxes to be centred.

Why stretch Is the Default on One and Absent on the Other

The asymmetry is deliberate. On the main axis, growth is already controlled per item by flex-grow, so a container-level "stretch everything" value would be redundant and would conflict with per-item control. On the cross axis there is no per-item growth property, so stretching has to be expressed at the container level, which is where align-items: stretch lives. Individual items opt out with align-self.

This also explains why the equal-height card row works with no height declarations anywhere. align-items defaults to stretch, so every card grows to the height of the tallest one. Setting align-items: flex-start collapses them all to their content heights, and setting align-self: start on one card opts just that one out.

align-items Versus align-content

One more distinction, since it is where the confusion usually lands. align-items aligns items within their line. align-content distributes the lines themselves along the cross axis, and only does anything when flex-wrap has produced more than one line and the container has extra cross-axis space. On a single-line container, align-content appears to do nothing at all, which is not a bug.


Key Code Explained

/* The single most common Flexbox pattern in production */
.navbar {
  display: flex;
  justify-content: space-between; /* main axis: logo left, links right */
  align-items: center;            /* cross axis: everything vertically centred */
}

/* Distribution values exist ONLY on justify-content */
.toolbar {
  display: flex;
  justify-content: space-evenly; /* equal gaps including the outer ones */
}
/* space-between: no outer gaps
   space-around:  outer gaps look half the inner ones
   space-evenly:  all gaps identical */

/* stretch and baseline exist ONLY on align-items */
.equal-height-cards {
  display: flex;
  /* align-items: stretch is the DEFAULT — this is why cards match
     the tallest one with no height declared anywhere */
}
.content-height-cards {
  display: flex;
  align-items: flex-start; /* opt out: each card takes its content height */
}
.one-card {
  align-self: start; /* opt a single item out */
}

/* baseline: align by the first line of text, not by the box */
.price-row {
  display: flex;
  align-items: baseline; /* $ and 99 and /mo share a text baseline */
}

/* justify-content does nothing when there is no free space */
.filled {
  display: flex;
  justify-content: space-between;
}
.filled > * {
  flex: 1; /* items consume all main-axis space -> nothing to distribute */
}

/* align-items vs align-content on a wrapped container */
.gallery {
  display: flex;
  flex-wrap: wrap;
  height: 500px;
  align-content: space-between; /* distributes the LINES */
  align-items: center;          /* positions items WITHIN each line */
}

The .navbar rule is the pattern to be able to write instantly, because it is the archetype: one property pins content to opposite ends of the main axis, the other centres it across the cross axis. Almost every header, toolbar, and list row in a real product is a variation of those two lines.

The .filled example explains the most common "justify-content is broken" report. flex: 1 on the children makes them absorb all available main-axis space, and since justify-content only distributes what is left over, there is nothing for it to do. The declaration is correct, the free space is not there.


Tradeoffs

Aspectjustify-contentalign-items
AxisMainCross
JobDistributes leftover free spacePositions items within the line
Default valueflex-startstretch
Has space-between / around / evenlyYesNo
Has stretch / baselineNoYes
Per-item overrideNone; use margin-inline-start: autoalign-self
Effect with no free spaceNoneStill applies

What Interviewers Actually Check

  • Whether you tie each property to an axis rather than to horizontal and vertical
  • Whether you can articulate the different jobs: distributing free space versus positioning within the line
  • Whether you know which values belong to which property and why
  • Whether you know align-items defaults to stretch and can connect that to equal-height columns
  • Whether you can explain why justify-content sometimes has no visible effect

Follow-Up Questions

  1. There is no justify-self in Flexbox. How do you push a single item to the far end of the main axis?
  2. What exactly does align-items: baseline align, and what happens to items that contain no text?
  3. How do space-around and space-evenly differ numerically for three items in a 600px container?
  4. Does gap interact with justify-content: space-between, and if so, how?
  5. How do the same two properties behave differently in Grid, where justify-items and justify-self both exist?

Common Candidate Mistakes

  • Memorising justify-content as the horizontal property and align-items as the vertical one, which breaks immediately in a column container
  • Expecting justify-content to reposition items that already fill the container, when it only distributes free space that in that case does not exist
  • Trying space-between on align-items, where the distribution values do not apply because items are positioned individually rather than distributed
  • Not knowing align-items defaults to stretch, and therefore adding explicit heights to make cards match when the behaviour was already free
  • Using align-items when the intent was to distribute wrapped lines, which is align-content, and concluding the property is broken on a single-line container

Interview Readiness Checklist

Before you leave this question, make sure you can answer:

  • Can you state which axis each property operates on, for any flex-direction?
  • Can you explain the different jobs of distributing free space versus positioning within the line?
  • Can you list the values unique to each property and say why they belong there?
  • Can you explain why align-items defaults to stretch and how a single item opts out?
  • Can you explain two reasons justify-content might appear to do nothing?

Summary

justify-content aligns along the main axis and align-items aligns along the cross axis, so in a default row container the first works horizontally and the second vertically, and in a column container they swap. Binding them to axes rather than to screen directions is what makes them predictable across responsive direction changes.

They also do different jobs. justify-content distributes leftover free space, which is why it owns space-between, space-around, and space-evenly, and why it has no visible effect when the items already fill the container. align-items positions each item within its line's cross-axis extent, which is why it owns stretch and baseline. stretch being its default is the reason equal-height flex columns happen without any height declarations, and align-self is the per-item escape hatch. There is no equivalent justify-self in Flexbox, so pushing one item to the far end of the main axis is done with an auto margin.

The remaining distinction worth holding is align-items versus align-content: the first positions items inside a line, the second distributes wrapped lines across the container's cross axis, and the latter does nothing at all until flex-wrap has produced more than one line.

Frequently Asked Questions

Why does align-items have a stretch value but justify-content does not?

Stretching along the main axis is handled by flex-grow on the items themselves, so the main axis distribution property does not need it. The cross axis has no equivalent per-item growth property, so stretch lives on align-items.

Does justify-content do anything when items fill the container?

No. It distributes free space, so if the items already consume all available main-axis space there is nothing left to distribute and it has no visible effect.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement