Codeskill

Learn to code, step by step

Flexbox gotchas and debugging

Flexbox gotchas and how to debug them. Flexbox is straightforward until it is not – usually when items refuse to shrink, alignment looks wrong, or gaps appear for no obvious reason. The intro series covered the basics; here are the failures you will meet weekly.

The min-width default (flex blowout)

Flex items have an implicit min-width: auto (or min-height: auto in column direction). They will not shrink below their content size unless you override it:

.toolbar {
  display: flex;
  gap: 1rem;
}

.toolbar__search {
  flex: 1;
  min-width: 0; /* allow shrinking below content width */
}

.toolbar__search input {
  width: 100%;
}

Without min-width: 0, a flex child with long text or a wide input pushes siblings off screen. This is the most common Flexbox bug in the wild.

flex shorthand vs longhand

flex: 1 expands to flex: 1 1 0% – grow, shrink, basis zero. flex: auto uses flex-basis: auto, which sizes from content first. They behave differently:

.equal-columns {
  display: flex;
  gap: 1rem;
}

.equal-columns > * {
  flex: 1 1 0; /* true equal width regardless of content */
}

.content-sized {
  flex: 1 1 auto; /* grow to fill, but start from content width */
}

When columns look uneven despite flex: 1, check whether something set flex-basis: auto elsewhere or a child is preventing shrink.

align-items vs align-self vs align-content

Three similarly named properties, three jobs:

  • align-items – cross-axis alignment of all flex items in the container
  • align-self – override for one item
  • align-content – spacing between flex lines when the container is taller than one line (multi-line flex only)
.card-row {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch; /* default - cards same height per row */
  align-content: flex-start; /* packed to top when extra vertical space */
  gap: 1rem;
}

.card-row .card--centred {
  align-self: center;
}

People often set align-items: center on the container and wonder why wrapped rows look spaced oddly. Check whether align-content is the property you wanted.

justify-content and margin auto

justify-content: space-between pushes first and last items to the edges. If the last item should sit on the right alone, margin-inline-start: auto on that item is often clearer:

.nav-bar {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav-bar__links {
  display: flex;
  gap: 1rem;
}

.nav-bar__account {
  margin-inline-start: auto;
}

Gap vs margin on flex items

gap on flex containers is well supported now. Prefer it over margin hacks on first/last children. If you still support very old browsers, margin on children with a negative margin on the container was the old pattern – you probably do not need it anymore.

Nested flex and height 100%

A flex child with height: 100% only works if every ancestor up the chain has a defined height. Often the fix is making the flex container fill available space:

.page {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

.page__main {
  flex: 1; /* grows to fill remaining viewport */
}

100dvh accounts for mobile browser chrome better than 100vh. Use it for full-height shells.

Order and accessibility

order changes visual order without changing DOM order. Screen readers and keyboard tab order follow the DOM. Do not use order to fix a markup problem – fix the markup, or use Grid grid-template-areas with sensible source order.

A debugging checklist

When a flex layout looks wrong, walk through this list:

  1. Is the container actually display: flex?
  2. Row or column? Check flex-direction.
  3. Any item need min-width: 0 or min-height: 0?
  4. Are you fighting flex-basis or fixed widths on children?
  5. Multi-line? Consider align-content and flex-wrap.
  6. Inspect in DevTools with the flex overlay – see computed flex values per item.

The next tutorial covers logical properties and writing-mode aware UI – the same flex and grid skills, but for layouts that are not strictly left-to-right.

PreviousGrid beyond the basics