CSS Flexbox Guide: flex-wrap, justify-content, flex-basis
Contents
- Anatomy of flexbox
- Row layout
- Column layout
- flex vs inline-flex
- Flex container properties
- flex-direction
- justify-content
- align-items
- flex-wrap
- align-content
- gap
- Flex item properties
- flex-grow
- flex-shrink
- flex-basis
- The flex shorthand
- align-self
- order
- Common flexbox patterns
- Push an item to the end with margin: auto
- Equal-width columns
- Responsive cards without media queries
- Sticky footer
- Flexbox vs Grid
- 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:
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-contentplaces items along the main axis.align-itemsplaces them along the cross axis.flex-directiondecides which way the main axis runs, so switching tocolumnswaps 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.
.container {
display: flex; /* flex-direction: row is the default */
}
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.
.container {
display: flex;
flex-direction: column;
}
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.
.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.
.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 */
}
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 endcenter: packed in the middle
.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;
}
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.
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. Withjustify-content: center, this is the easiest way to center a div.flex-start/start: aligned to the topflex-end/end: aligned to the bottombaseline: aligned so the first lines of text sit on the same baseline, handy for items with different font sizes
.container {
display: flex;
align-items: stretch; /* default */
align-items: center;
align-items: flex-start;
align-items: flex-end;
align-items: baseline;
}
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 belowwrap-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.
.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;
}
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.
.container {
display: flex;
flex-wrap: wrap; /* required: align-content needs several lines */
height: 400px;
align-content: flex-start;
}
With space-between, space-around and space-evenly, the free space goes between the lines instead of the items.
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.
.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.
.sidebar {
flex-grow: 0; /* default: keeps its size */
}
.main {
flex-grow: 1; /* takes all the remaining space */
}
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.
.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.
.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.
.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.
.container {
display: flex;
align-items: flex-start;
}
.special {
align-self: flex-end; /* only this item goes to the bottom */
}
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.
.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.
.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().
.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.
.cards {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 250px;
}
Sticky footer
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.
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.
Related: CSS tips you won’t see in most tutorials, CSS calc(), position absolute vs relative and the CSS tutorial.