CSS Flexbox Guide: flex-wrap, justify-content, flex-basis

By Gergő Pásztor
Contents
  1. Anatomy of flexbox
  2. Row layout
  3. Column layout
  4. flex vs inline-flex
  5. Flex container properties
  6. flex-direction
  7. justify-content
  8. align-items
  9. flex-wrap
  10. align-content
  11. gap
  12. Flex item properties
  13. flex-grow
  14. flex-shrink
  15. flex-basis
  16. The flex shorthand
  17. align-self
  18. order
  19. Common flexbox patterns
  20. Push an item to the end with margin: auto
  21. Equal-width columns
  22. Responsive cards without media queries
  23. Sticky footer
  24. Flexbox vs Grid
  25. FAQ

Flexbox (the flexible box layout) is a CSS layout model for arranging items in a row or a column. It spaces them out, aligns them, and lets them grow or shrink to fill the space, without floats or fixed widths. You turn it on with one line on the parent: display: flex.

This guide covers every flexbox property with code you can copy, plus the patterns you’ll use most. New to CSS? Start with the CSS tutorial first.

The demo below uses most of them: a navigation bar with justify-content and align-items, and cards that wrap with flex-wrap and flex. Resize the window to see the cards reflow.

Demo:

Logo
Card 1
Card 2
Card 3
Card 4

Anatomy of flexbox

A flex container has two axes. The main axis runs in the direction the items are laid out (left to right by default), and the cross axis runs perpendicular to it.

  • justify-content places items along the main axis.
  • align-items places them along the cross axis.
  • flex-direction decides which way the main axis runs, so switching to column swaps what the two properties do.

Row layout

The default. All children sit next to each other on one line, along the main axis, from left to right.

css
.container {
  display: flex; /* flex-direction: row is the default */
}
CSS Flexbox - Row Layout

Column layout

The column layout stacks children under each other. The axes swap: the main axis now runs top to bottom, so justify-content works vertically and align-items horizontally.

css
.container {
  display: flex;
  flex-direction: column;
}
CSS Flexbox - Column Layout

flex vs inline-flex

display: flex makes a block-level container: it starts on a new line and takes the full available width. display: inline-flex makes an inline-level container: it sits inside a line of text and is only as wide as its content. The children are laid out the same way in both.

css
.toolbar {
  display: flex;        /* full width, on its own line */
}

.badge {
  display: inline-flex; /* flows with the text around it */
  align-items: center;
  gap: 4px;
}

Flex container properties

These go on the parent (the element with display: flex) and control all of its children at once.

flex-direction

Sets the direction of the main axis. There are four values: row (default), row-reverse, column and column-reverse. The reverse values flip the visual order only; the HTML order stays the same.

css
.container {
  display: flex;
  flex-direction: row;            /* left to right (default) */
  flex-direction: row-reverse;    /* right to left */
  flex-direction: column;         /* top to bottom */
  flex-direction: column-reverse; /* bottom to top */
}
CSS Flexbox - flex-direction

justify-content

justify-content distributes the items along the main axis, horizontally in a row. The default packs them at the start. The values you’ll use:

  • flex-start / start: packed at the start (default behavior)
  • flex-end / end: packed at the end
  • center: packed in the middle
css
.container {
  display: flex;
  justify-content: flex-start;    /* default */
  justify-content: flex-end;
  justify-content: center;
  justify-content: space-between;
  justify-content: space-around;
  justify-content: space-evenly;
}
CSS Flexbox - justify-content

The space-* values share the free space between the items:

  • space-between: first item at the start, last at the end, equal space between the rest. The classic “logo left, menu right” layout.
  • space-around: equal space around each item, so the edges get half as much as the gaps between items.
  • space-evenly: exactly the same space between the items and at both edges.

justify-content only has a visible effect when there’s free space left. If the items already fill the row, there’s nothing to distribute.

CSS Flexbox - justify-content

align-items

align-items aligns the items along the cross axis, vertically in a row. The default, stretch, makes every item as tall as the container (or as wide, in a column). The other values:

  • center: centered on the cross axis. With justify-content: center, this is the easiest way to center a div.
  • flex-start / start: aligned to the top
  • flex-end / end: aligned to the bottom
  • baseline: aligned so the first lines of text sit on the same baseline, handy for items with different font sizes
css
.container {
  display: flex;
  align-items: stretch;     /* default */
  align-items: center;
  align-items: flex-start;
  align-items: flex-end;
  align-items: baseline;
}
CSS Flexbox - align-items

flex-wrap

By default, flex items all stay on one line and shrink to fit, even if that squeezes them or makes them overflow. flex-wrap lets them move onto new lines instead, which is what makes flexbox layouts responsive.

  • nowrap: everything on one line (default)
  • wrap: items that don’t fit move to a new line below
  • wrap-reverse: same, but new lines go above

Items only wrap when they can’t shrink any further, so give them a minimum size: a flex-basis, a width or a min-width. flex-flow is a shorthand for flex-direction and flex-wrap together.

css
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.cards > * {
  flex: 1 1 200px; /* at least 200px, then wrap */
}

/* Shorthand for flex-direction + flex-wrap */
.cards {
  flex-flow: row wrap;
}
CSS Flexbox - flex-wrap

align-content

When items wrap onto several lines, align-content distributes those lines along the cross axis, the same way justify-content distributes items along the main axis. It does nothing on a single line, and it needs extra space in the container (for example a set height) to have a visible effect. The default behaves like stretch, and the other values are the same as for justify-content: flex-start, flex-end, center and the space-* values.

css
.container {
  display: flex;
  flex-wrap: wrap; /* required: align-content needs several lines */
  height: 400px;
  align-content: flex-start;
}
CSS Flexbox - align-content

With space-between, space-around and space-evenly, the free space goes between the lines instead of the items.

CSS Flexbox - align-content

gap

gap sets the space between flex items, without adding space at the outer edges. Before it existed, people used margins on the items and then removed the margin from the first or last one. gap takes one value for both directions, or two: row-gap then column-gap. It works in every current browser.

css
.container {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;      /* same space between rows and columns */
  gap: 24px 16px; /* row-gap column-gap */
}

Flex item properties

These go on the children and control how each one sizes and positions itself.

flex-grow

flex-grow decides how the free space in the container is shared. It takes any number of 0 or more, and the default is 0: items don’t grow. Give an item flex-grow: 1 and it takes all the leftover space. Give two items 1 and 2, and the second gets twice as much of the free space. That doesn’t make it twice as wide.

css
.sidebar {
  flex-grow: 0; /* default: keeps its size */
}

.main {
  flex-grow: 1; /* takes all the remaining space */
}
CSS Flexbox - flex-grow

flex-shrink

flex-shrink is the opposite: it decides how items give up space when there isn’t enough. The default is 1, so every item shrinks. Set it to 0 on things that must keep their size, like icons, avatars or a fixed-width sidebar.

css
.icon {
  flex-shrink: 0; /* never squeezed */
  width: 24px;
}

.title {
  flex-shrink: 1; /* default: shrinks when space runs out */
  min-width: 0;   /* lets long text shrink and truncate */
}

flex-basis

flex-basis is an item’s starting size along the main axis, before flex-grow and flex-shrink are applied. The default, auto, uses the item’s width (or height in a column), or its content size if none is set.

flex-basis vs width: in a row, flex-basis wins over width, and it follows the main axis, so it becomes the height in a column. min-width and max-width still apply on top.

css
.item {
  flex-basis: 200px; /* start at 200px, then grow or shrink */
}

.item {
  flex-basis: 0;     /* ignore the content size: share all space equally */
  flex-grow: 1;
}

The flex shorthand

flex sets flex-grow, flex-shrink and flex-basis in one go, and it’s the recommended way to write them. The values you’ll see most:

  • flex: 1 = 1 1 0%: grow and shrink equally, ignoring content size. Use it for equal columns.
  • flex: auto = 1 1 auto: grow and shrink, starting from the content size.
  • flex: none = 0 0 auto: fixed at its content or width.
  • flex: 0 1 auto: the default.
css
.item {
  /* flex: <grow> <shrink> <basis> */
  flex: 1 1 200px;
}

.equal  { flex: 1; }    /* 1 1 0% */
.auto   { flex: auto; } /* 1 1 auto */
.fixed  { flex: none; } /* 0 0 auto */

align-self

align-self overrides the container’s align-items for a single item. It takes the same values: stretch, center, flex-start, flex-end and baseline.

css
.container {
  display: flex;
  align-items: flex-start;
}

.special {
  align-self: flex-end; /* only this item goes to the bottom */
}
CSS Flexbox - align-self

order

order changes where an item appears without touching the HTML. It takes any whole number, including negatives. The default is 0, and lower numbers come first.

Use it with care: it only changes the visual order. Screen readers and keyboard Tab navigation still follow the HTML, so don’t use order for content whose order matters.

css
.first {
  order: -1; /* moves before all items with order: 0 */
}

.last {
  order: 1;
}

Common flexbox patterns

Most real layouts are one of these.

Push an item to the end with margin: auto

An auto margin on a flex item takes up all the free space on that side. It’s the simplest way to push one item, like a “Sign up” button, to the far end of a navigation bar.

css
.nav {
  display: flex;
  gap: 16px;
}

.nav .signup {
  margin-left: auto; /* everything after it goes to the right */
}

Equal-width columns

flex: 1 on every child gives equal columns that always fill the row, whatever their content. If you need exact widths with gaps instead, see CSS calc().

css
.columns {
  display: flex;
  gap: 24px;
}

.columns > * {
  flex: 1;
}

Responsive cards without media queries

Cards with a minimum width that grow to fill the row and wrap when there’s no more room. This is the card grid in the demo above.

css
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.card {
  flex: 1 1 250px;
}

Keep the footer at the bottom of the screen on short pages: make the page a column at least as tall as the viewport, and let the main content grow.

css
body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

main {
  flex: 1; /* pushes the footer down */
}

Flexbox vs Grid

Flexbox is one-dimensional: it lays items out in a row or a column and sizes them based on their content. Grid is two-dimensional: you define rows and columns, and items are placed into that structure.

A good rule of thumb: use flexbox for components (navigation bars, toolbars, buttons with icons, card rows) and grid for page layouts and anything that needs to line up in both directions. They work well together: a grid for the page, flexbox inside each part.

FAQ

Where should I use flexbox?

Anywhere you need to line items up in one direction: navigation bars, toolbars, button groups, centering, card rows, form controls and sticky footers.

What is the difference between flex and inline-flex?

Both lay out their children the same way. flex makes the container block-level (full width, on its own line), inline-flex makes it inline-level (as wide as its content, flowing with text).

Why is flex-wrap not working?

Usually the items have no minimum size, so they keep shrinking instead of wrapping. Give them a flex-basis, width or min-width. Also check that flex-wrap: wrap is on the container, not on the items.

What’s the difference between flex-basis and width?

flex-basis is the starting size along the main axis, before growing and shrinking, and it overrides width in a row. It follows the axis, so in a column it controls the height.

What’s the difference between justify-content and align-items?

justify-content works along the main axis (horizontal in a row), align-items along the cross axis (vertical in a row). In a column, they swap.

What does flex: 1 mean?

It’s short for flex: 1 1 0%: the item can grow and shrink, and starts from zero, so all items with flex: 1 end up the same size.

Is flexbox supported in all browsers?

Yes. Flexbox works in every browser in use today, and gap for flexbox has been supported everywhere since 2021.