CSS Flexbox Guide: Layout Without the Guesswork (2026) - CSS tutorial cover with bold white title lettering on a dark navy grid background.

Quick answer: CSS flexbox lays out items along one axis — a row or a column. Set display: flex on the container, use justify-content for the main axis and align-items for the cross axis, and gap for spacing. It is the right tool for navigation bars, button rows, card contents and any “line them up” problem. Reach for Grid once you need rows and columns together.The sections below cover CSS flexbox in the order you need it: the container properties, the shorthand that trips people up, three layouts worth memorising, then wrapping — the CSS flexbox behaviour that surprises most people.

Quick answer card that answers 'css flexbox' in plain language for beginners.
css flexbox guide roadmap listing the 5 sections in reading order.

The container does the work

Flexbox is controlled from the parent. Three properties answer most layout questions:

.toolbar {
  display: flex;
  justify-content: space-between;  /* main axis: spread items apart */
  align-items: center;             /* cross axis: centre vertically */
  gap: 0.75rem;
}
PropertyAxisCommon values
justify-contentMainflex-start, center, space-between, space-around
align-itemsCrossstretch, center, flex-start, baseline
flex-directionSets which axis is mainrow, column
flex-wrapAllows wrappingnowrap, wrap

The one mental shift: justify-content always works along whatever direction you chose. Switch to flex-direction: column and the two properties swap their visual effect — justify-content now centres vertically.

The three-item flex shorthand

How an individual item grows and shrinks is set with the flex shorthand: grow factor, shrink factor and base size.

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

.sidebar { flex: 0 0 240px; }   /* fixed: never grow or shrink */
.content { flex: 1 1 auto; }    /* fill the rest */
.label   { flex: none; }        /* size to content */
  • flex: 1 — grow to fill the free space, shrink if needed. The most common value.
  • flex: none — keep the natural size.
  • flex: 0 0 240px — a fixed 240px that cannot grow or shrink.
css flexbox concept map connecting the related topics this guide covers.

Three CSS flexbox layouts worth memorising

Centre anything — the classic problem, solved in three lines:

.center {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100svh;
}

Sticky footer — a column where the middle grows so the footer sits at the bottom on short pages:

body { display: flex; flex-direction: column; min-height: 100svh; }
main { flex: 1; }

Media object — an avatar and text side by side, with the text taking the remaining width:

.media { display: flex; gap: 1rem; align-items: flex-start; }
.media img { flex: none; border-radius: 50%; }
.media .body { flex: 1; min-width: 0; }  /* min-width stops long words overflowing */

That min-width: 0 is a detail worth remembering. Flex items default to a minimum size based on their content, so a long unbreakable string can refuse to shrink and overflow the row. Setting it to zero lets the item shrink and the text wrap normally.

Wrapping cards with CSS flexbox

Flexbox can also build a responsive card row without media queries, by allowing wrap and giving each card a sensible basis.

.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.cards > * {
  flex: 1 1 260px;   /* grow, shrink, wrap once narrower than 260px */
}

Each card tries to be at least 260px, grows to share the row, and wraps to the next line when the space runs out. When you need the cards to align strictly into equal columns and rows, that is the point to switch to CSS Grid.

Keep that axis discipline and CSS flexbox stays predictable in every layout you build. Next: CSS Grid. To learn layout with a mentor on real designs, Ampersand Academy teaches web development one-to-one.

CSS flexbox mistakes and how to fix them

Most flexbox bugs are axis mistakes. The container has exactly one main axis and one cross axis, and every property names one of them, so a fix applied on the wrong axis does nothing at all. When a row of icons refuses to centre vertically, the instinct is to add justify-content, but that moves them horizontally; align-items is the vertical control in a row and becomes the horizontal one in a column. Before changing any value, name the axes out loud for the flex direction you are using. That single habit removes most of the trial and error from CSS flexbox debugging and turns a ten-minute experiment into a two-second correction.

Wrapping is the second surprise. Items only wrap when flex-wrap allows it, and once they do, each line becomes its own flex line with its own alignment, so justify-content distributes the items on each row separately rather than across the whole container. That is why a wrapping toolbar sometimes leaves a ragged gap at the end of the last row while looking perfect with three items on screen. Decide deliberately whether the row is meant to wrap; if it is, add row and column gaps so the lines breathe, and if it is not, let items shrink instead of forcing widths. Stated intent in the container beats widths guessed at on each child.

Shrinking deserves explicit control. The default is that flex items can shrink below their base size, so an image or a code sample in a CSS flexbox row compresses until it is unreadable, while the text beside it keeps its natural width. The shorthand’s middle value sets the growth factor and the third sets the shrink factor, so giving a fixed-content child a shrink factor of zero keeps its width intact and forces its siblings to absorb the difference. Pair that with a sensible minimum width and the layout stops depending on content nobody controls, which is the difference between a toolbar that survives long labels and one that breaks the first time a translation arrives.

Order in the DOM still matters for accessibility and for wrapping, and the order property is rarely the right fix for a visual rearrangement. Changing visual order without changing source order splits keyboard navigation from what the eye follows, and on narrow screens where items wrap, the reordered sequence produces confusing jumps. When a design genuinely needs a different arrangement, prefer moving the elements in the markup so the reading order is correct everywhere, and reserve the order property for the rare interface where the source order is already right but a single breakpoint differs. In CSS flexbox you can rearrange pixels cheaply; rearranging the sequence people read is a different, costlier operation.

Finally, remember what flexbox is not for. It aligns along one axis, so a two-dimensional layout with independent rows and columns belongs to grid, and forcing flexbox to emulate one produces the nested containers and magic numbers that give layout systems a bad name. A useful rule is that flexbox distributes space along a line and grid places items on a plane: navigation bars, button groups, metadata rows and card footers are flexbox problems, while dashboards, galleries and page scaffolding are grid problems. Choosing the right tool first is most of the work; CSS flexbox is excellent precisely because it does one job, and layouts stay simple when you let it.

css flexbox guide coverage grid showing every section covered in this article.

CSS flexbox alignment beyond the basics

justify-content and align-items cover most cases, but two properties get skipped until they cause pain: align-self and align-content. They solve different problems. align-self overrides the container’s align-items for one specific child. align-content only activates when flex-wrap: wrap is set and there are multiple lines — it controls spacing between those lines, not between items inside a single line.

Mixing them up produces bugs that look unsolvable. If your wrapped card grid has mysterious vertical gaps between rows, align-content is almost certainly set to space-between by default stretch behaviour. Set it explicitly to flex-start and the rows pack to the top as expected. This is one of the most common css flexbox bugs filed as a browser issue that turns out to be a missing explicit value.

Using align-self for one-off overrides

A toolbar with five icons centred and one pinned to the bottom of the container is a single align-self: flex-end on that child. No wrapper, no absolute positioning. The rule is: use align-items to set the default for every child, then use align-self to deviate for exactly one. Adding a wrapper div for this is unnecessary code that slows future edits.

.toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.toolbar .badge {
  align-self: flex-end; /* this one item drops to the bottom */
  margin-bottom: 2px;
}

.toolbar { display: flex; align-items: center; gap: 0.5rem; }.toolbar .badge { align-self: flex-end; /* this one item drops to the bottom */ margin-bottom: 2px; }

That two-line override replaces what used to need relative positioning and pixel nudging. Keep it in the muscle memory for any css flexbox row where one child needs a different vertical position than its siblings.

CSS flexbox gap, margin and spacing decisions

The gap property is the right default for spacing flex children. It puts space between items only — never on the outer edges — which eliminates the old negative-margin tricks. Use it first. Reach for margin on individual children only when one specific item needs different spacing from the rest, such as a “logout” button pushed to the far right of a nav bar.

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

.nav .logout {
  margin-left: auto; /* pushes this item to the far end */
}

.nav { display: flex; align-items: center; gap: 1rem; }.nav .logout { margin-left: auto; /* pushes this item to the far end */ }

margin: auto in a css flexbox container absorbs all remaining free space in whatever direction it is applied. This is the correct way to push one item to the opposite end without reaching for justify-content: space-between, which would spread every item. Knowing this removes a whole class of layout workarounds involving absolute positioning or extra wrapper elements.

Gap versus padding on the container

Padding on the flex container creates space between the container’s border and its children. Gap creates space between children only. Both are sometimes needed together: padding to breathe from the edge, gap to space the items. Setting padding on the container and gap between children is not redundant — they control different distances. Confusing the two produces either a cramped edge or unwanted space before the first child.

One pattern worth keeping: when a flex container is also a card, set padding on the container and gap between its inner items. The card’s outer edge stays controlled by the parent’s gap. This two-level separation means spacing never needs magic numbers and responds cleanly when the design scales up or font size changes.

Building responsive layouts with css flexbox and no media queries

The wrapping cards pattern from earlier uses flex: 1 1 260px. Extending that idea further: combining flex-basis with clamp() lets the basis itself respond to viewport width. This is a genuinely modern technique most developers have not applied yet.

.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.cards > * {
  flex: 1 1 clamp(200px, 30%, 340px);
  /* ponytail: clamp() sets a responsive basis range without a breakpoint */
}

.cards { display: flex; flex-wrap: wrap; gap: 1rem; }.cards > * { flex: 1 1 clamp(200px, 30%, 340px); /* ponytail: clamp() sets a responsive basis range without a breakpoint */ }

The item’s basis will be at least 200px, at most 340px, and 30% of the container between those bounds. Items wrap naturally. No @media query is written. This works because css flexbox wrapping is inherently content-aware: the browser calculates available space and wraps when the basis no longer fits, which is exactly what a breakpoint would have triggered manually.

This approach has a ceiling: when you need items to snap to exact column counts rather than filling available space fluidly, Grid’s repeat(auto-fill, minmax()) is more direct. Use the flexbox version when fluid stretching is acceptable; use Grid when column count must be exact at a given width.

Handling overflow and scroll inside css flexbox containers

A horizontal scroll row — think a mobile story tray or a tab bar — is one of the most practical css flexbox patterns that articles skip. The setup is small but the pitfalls are real. The container needs overflow-x: auto and must not wrap. Children must not shrink. Without explicit shrink prevention, children compress instead of triggering scroll.

.scroll-row {
  display: flex;
  gap: 0.75rem;
  overflow-x: auto;
  flex-wrap: nowrap;
  scrollbar-width: thin; /* Firefox */
  -webkit-overflow-scrolling: touch; /* iOS momentum */
}

.scroll-row > * {
  flex: 0 0 auto; /* no grow, no shrink, natural size */
}

.scroll-row { display: flex; gap: 0.75rem; overflow-x: auto; flex-wrap: nowrap; scrollbar-width: thin; /* Firefox */ -webkit-overflow-scrolling: touch; /* iOS momentum */ }.scroll-row > * { flex: 0 0 auto; /* no grow, no shrink, natural size */ }

The flex: 0 0 auto on each child is the critical line. Without it, the browser tries to fit all children into the container width and collapses them. With it, each child holds its natural size and the container scrolls. This is a case where the shrink factor — the middle value of the flex shorthand — matters as much as the grow factor.

Accessibility note: a scroll container needs keyboard focusability for users who cannot use a pointer. Add tabindex="0" to the container so keyboard users can focus it and scroll with arrow keys. This is a mandatory step, not optional polish, any time you build a scroll row with css flexbox.

A step-by-step css flexbox debugging workflow

When a flexbox layout breaks, guessing at properties wastes time. This sequence finds the cause in under two minutes, applied in order.

  1. Open DevTools and click the flex badge next to the container element. Every modern browser renders a flexbox overlay showing axes, free space and item boundaries. Look at it before touching any CSS.
  2. Confirm the flex direction. Read the overlay’s arrow or check the computed flex-direction. Name the main axis and the cross axis out loud before any change.
  3. Check whether the container has a defined size on the cross axis. align-items: center on a container with no height centres items within zero space — nothing moves. Give the container a height or min-height first.
  4. Check flex-wrap. If items are overflowing sideways, wrapping is off and items are not permitted to move to the next line. Add flex-wrap: wrap or reduce the flex basis.
  5. Check min-width on overflowing children. A child refusing to shrink almost always has an implicit minimum size from its content. Add min-width: 0 to that child and test again.

Following this order means the common 80% of css flexbox bugs resolve at step two or three. The remaining bugs — unexpected stacking, collapsed containers, text overflow — are nearly always caught at steps four and five. The DevTools flex overlay makes step one visual rather than conceptual, which is the single biggest time saving available in modern browser tooling for layout work.

One final check outside this sequence: inherited display values. A child that is itself a flex container but has no explicit flex shorthand on its children inherits no sizing rules — its children size to content, which may look like a parent bug. Inspect one level deeper before assuming the outer container is wrong.

Frequently asked questions

What is the difference between Flexbox and Grid?

Flexbox arranges items along one axis, a row or a column, and is driven by content size. Grid arranges items in rows and columns at once and is driven by a defined track structure.

How do I centre a div with Flexbox?

Set display flex, justify-content center and align-items center on the container, and give it a height such as min-height 100svh. The child is centred on both axes.

What does flex 1 mean?

It is shorthand for grow to fill available space and shrink if needed, starting from the content size. It is the most common way to make one item take the remaining room.

Why is my flex item overflowing its container?

Flex items have a content-based minimum size, so a long word can refuse to shrink. Set min-width 0 on the item so it can shrink and its text can wrap.

Should I use gap or margins in Flexbox?

Use gap. It spaces items evenly without margin collapsing or trailing margins on the last item, and it works the same in Flexbox and Grid.

Last updated on · Written by