CSS Flexbox Explained: A Practical Guide to One-Dimensional Layout
What is CSS flexbox?
CSS flexbox (the Flexible Box Layout module) is a layout system for arranging items in one dimension, either a row or a column. You set display: flex on a parent, and its direct children become flex items that can grow, shrink, wrap and align along two axes. It suits navigation bars, toolbars, card rows and centring content.
Flex containers, flex items and the two axes
Flexbox has two roles. The flex container is the element with display: flex (or inline-flex). Its direct children are flex items. Grandchildren are not affected unless their own parent is also a flex container.
Every flex container has a main axis, the direction items are laid out in, and a cross axis at right angles to it. With the default flex-direction: row, the main axis runs horizontally in left-to-right languages and the cross axis runs vertically. Switch to column and the axes swap. Nearly every flexbox property is defined in terms of these axes, so knowing which way the main axis runs is the first thing to check when a layout misbehaves.
| Property | Set on | What it controls |
|---|---|---|
| flex-direction | Container | Main axis direction: row, row-reverse, column, column-reverse |
| flex-wrap | Container | Whether items move onto new lines when space runs out |
| justify-content | Container | Distribution of items along the main axis |
| align-items | Container | Alignment of items on the cross axis within a line |
| align-content | Container | Spacing between lines when items wrap |
| gap | Container | Fixed space between items and between lines |
| flex, order, align-self | Item | How one item sizes, where it appears and how it aligns |
How flexbox distributes space and alignment
justify-content works on the main axis. Common values are flex-start, center, flex-end, space-between (first and last items touch the edges) and space-evenly. align-items works on the cross axis; its default, stretch, makes items fill the height of a row, which is why flex columns often look equal-height without any extra code.
By default all items stay on one line and shrink to fit. Add flex-wrap: wrap to let them flow onto new lines. Once there are several lines, align-content controls how those lines share the extra cross-axis space. On a single-line container it has no effect, a frequent source of confusion.
flex-grow, flex-shrink and flex-basis
Each item has three sizing values. flex-basis is its starting size before free space is shared out. flex-grow is how many shares of leftover space it takes. flex-shrink is how readily it gives up space when there is not enough. The initial values are 0 1 auto: items do not grow, may shrink, and start from their content or width.
.item { flex: 1; } /* 1 1 0% : equal shares of the row */
.item-auto { flex: auto; } /* 1 1 auto : grows from its content size */
.item-fixed { flex: none; } /* 0 0 auto : never grows or shrinks */
.sidebar { flex: 0 0 250px; }/* stays 250px wide */Prefer the flex shorthand over setting the three properties separately, because it resets any values you leave out to sensible defaults.
Common flexbox layout patterns with code
Navigation bar with logo left and links right
.site-nav {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.site-nav ul { display: flex; gap: 1.5rem; list-style: none; margin: 0; padding: 0; }Centring anything in both directions
.hero {
display: flex;
justify-content: center; /* main axis */
align-items: center; /* cross axis */
min-height: 60vh;
}A wrapping row of cards
.cards { display: flex; flex-wrap: wrap; gap: 1.5rem; }
.card { flex: 1 1 250px; } /* at least 250px, then share the rest */Sticky footer on short pages
body { display: flex; flex-direction: column; min-height: 100vh; margin: 0; }
main { flex: 1; } /* main absorbs spare height, pushing the footer down */In the card row, the last line may contain fewer cards that stretch wider than those above. That is how flexbox is designed to behave; if you want every card in strict columns, use CSS grid tracks instead.
Building a flexbox layout step by step
- Write the HTML first, with a parent element wrapping the items you want to arrange.
- Add
display: flexto the parent and decide whether the main axis is a row or a column. - Add
gapfor spacing rather than margins on each item. - Set
justify-contentfor main-axis distribution andalign-itemsfor cross-axis alignment. - Decide whether items should wrap; if so, add
flex-wrap: wrapand give items a sensibleflex-basis. - Give individual items a
flexvalue where they need to grow or stay fixed. - Open your browser dev tools, where the flexbox inspector overlays the axes and free space, and resize the window to check behaviour at narrow widths.
Good flexbox habits, the order property and when to choose grid
The order property and the -reverse directions change only the visual order. Keyboard focus and screen readers still follow the source order of the HTML, so a visitor tabbing through the page can jump around unpredictably. Change the HTML when the reading order genuinely needs to change, and keep order for small visual tweaks that do not affect meaning.
- Use flexbox when content should decide sizes and items flow in one direction, such as menus, button groups and media objects.
- Use grid when you need rows and columns to line up with each other, or when the layout should decide sizes.
- Combining both is normal: a grid for the page and flexbox inside each component.
- Add
min-width: 0to a flex item holding long text or code that overflows, because flex items will not shrink below their content size by default.
Practical exercise: build a responsive site header
Create an index.html with a header containing a logo, four links and a "Sign in" button, using the semantic structure covered in our HTML basics guide. Style it with flexbox only.
- Place the logo on the left and the links and button on the right, vertically centred.
- Below 600px wide, let the links wrap underneath the logo with consistent gaps.
- Add a three-card row beneath the header with
flex: 1 1 250pxand check how it wraps. - Add a footer that stays at the bottom of the window even when the page has little content.
You are done when the header looks tidy from 320px to full desktop width, the footer never floats mid-screen, and tabbing through the links follows the visual order. Building layouts like this from scratch is part of the front-end work in SkillNewton's PHP foundation course.
Common mistakes
- Setting
justify-contentoralign-itemson the item instead of the flex container. - Expecting
align-contentto work on a container whose items do not wrap. - Using the
orderproperty to rearrange meaningful content, which breaks keyboard and screen reader order. - Adding margins to every item for spacing when a single
gapon the container is simpler. - Forcing a two-dimensional grid of aligned rows and columns with flexbox and percentage widths.
Frequently asked questions
Is flexbox better than CSS grid?
Neither replaces the other. Flexbox handles one direction at a time and lets content drive sizes, while grid layout controls rows and columns together. Most sites use both.
Does gap work with flexbox in all browsers?
Yes. The gap property has worked in flex containers in all current major browsers for several years, so you no longer need negative-margin workarounds.
Why does my flex item overflow its container?
Flex items have an automatic minimum size equal to their content, so long words, URLs or images can push them wider. Setting min-width: 0 or overflow: hidden on the item allows it to shrink.
Do I need media queries with flexbox?
Often fewer than you expect. Wrapping and flex-basis handle many cases, and you can add responsive breakpoints where the design genuinely needs to change.