Course outline · 0% complete

0/30 lessons0%

Course overview →

Aligning and distributing

lesson 6-2 · ~9 min · 19/30

Distributing along the main axis

Most day-to-day layout tickets are placement tickets, asking to center something, to push two things to opposite ends, or to explain why something is misaligned. The two properties in this lesson close nearly all of them.

.row {
  display: flex;
  justify-content: space-between;
}
ValueEffect
flex-startpack items at the start, the default
centerpack items in the middle
flex-endpack items at the end
space-betweenfirst and last touch the edges, equal gaps between
space-aroundequal space around every item

For the cross axis, align-items: center is the value typed most often, since it vertically centers the items of a row.

gap: 16px adds fixed space between items and never at the edges, which is far cleaner than putting margins on the children and then fighting the extra margin on the last one.

flex-startcenterflex-endspace-betweenspace-aroundOnly space-between puts the first and last items flush against the container edges.
Five values of justify-content applied to the same three items, all along the main axis.

The two recipes worth knowing cold

Perfect centering puts one child dead center in its parent, and it is the recipe behind almost every hero section, meaning the full-screen opening banner from lesson 5-3.

.hero {
  display: flex;
  justify-content: center; /* main axis */
  align-items: center;     /* cross axis */
  min-height: 100vh;       /* vh from lesson 5-3 */
}

The stretchy middle uses flex-grow to hand leftover space to one item. The classic header has a logo, a search box filling whatever is left, then buttons.

.search {
  flex-grow: 1;
}
flex-growShare of leftover space
0none, the item stays content-sized
1one share
2twice as much as an item with 1

Items default to 0, so nothing stretches until asked. Grow values split the leftover space proportionally rather than setting widths, which is why the header keeps working at any window size.

Centering on both axes

The pair that centers a child horizontally and vertically in a flex row is justify-content: center with align-items: center.

One property per axis, with justify-content centering along the main horizontal axis and align-items along the cross vertical axis.

PropertyAxis in a row
justify-contenthorizontal
align-itemsvertical

Pairs such as text-align with vertical-align are not how flex containers are controlled, and they belong to text and table-cell layout instead. Reaching for them inside a flex container is a common early habit that produces no effect.

A group of cards centered on both axes

Both alignment properties set to center, on a container tall enough for the centering to be visible.

CSS

.stage {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 220px;
  border: 2px dashed gray;
}

.card {
  padding: 16px 24px;
  margin: 4px;
  background: #d4af37;
  border-radius: 8px;
  font-family: sans-serif;
}
DeclarationAxisResult
display: flexnoneenables the other two
justify-content: centermain, horizontalgroup sits in the middle
align-items: centercross, verticalgroup sits halfway down
height: 220pxnonegives the cross axis room

display: flex comes first, because the other two do nothing without it.

The explicit height matters more than it looks. A container that is only as tall as its content has nothing to center within, so vertical centering appears to fail when the real problem is a missing height.

Computing space-between by hand

spaceBetween(containerWidth, itemWidth, count) returns the x position of each item's left edge, with the first item at 0, the last touching the right edge, and the leftover space split into equal gaps.

function spaceBetween(containerWidth, itemWidth, count) {
  const leftover = containerWidth - itemWidth * count;
  const gap = leftover / (count - 1);
  const positions = [];
  for (let i = 0; i < count; i++) {
    positions.push(i * (itemWidth + gap));
  }
  return positions;
}

console.log(spaceBetween(500, 100, 3));
console.log(spaceBetween(400, 50, 2));

Output

[ 0, 200, 400 ]
[ 0, 350 ]
StepFormula
leftovercontainerWidth − itemWidth × count
gapleftover ÷ (count − 1)
position of item ii × (itemWidth + gap)

Three 100px items in 500px leave 200px, split into 2 gaps of 100px each. Each item starts one stride of itemWidth + gap after the previous one.

The divisor is count - 1 rather than count because the gaps sit only between items, never at the edges. That single detail is the whole difference between space-between and space-around.