How to Build a CSS Flexbox Layout (with Real Examples)
A practical guide to flexbox: when to use it (and when not to), the six properties that matter, the common gotchas with align-items and flex-basis, and how to experiment with a live layout in your browser before committing it to a stylesheet.
Flexbox is the right layout model for one-dimensional layouts: a row of items, a column of items, anything where you want to align items along a single axis and have flexible spacing. The six properties that matter are display, flex-direction, flex-wrap, justify-content, align-items, and gap. The most common mistakes are mixing up justify-content (main axis) with align-items (cross axis), and forgetting that flex children shrink by default. A browser playground lets you edit the values and see the result live, without writing a full HTML file each time.
Flexbox is the layout model that finally made CSS layout reasonable. Before flexbox, you floated divs, cleared them, and prayed. After flexbox, you have a one-dimensional layout primitive that handles alignment, distribution, and sizing with six properties. This post covers when to use flexbox (and when not to), the six properties that matter, the most common mistakes, and how to experiment with a live layout in your browser before committing it to a stylesheet.
When to use flexbox (and when not to)
Flexbox is for one-dimensional layouts: a row of items, a column of items, anything where the items are arranged along a single axis and you want flexible spacing. Concrete cases:
- A row of navigation links. Items left-aligned, with equal space between them.
- A column of form fields. Labels above inputs, all aligned to the same width.
- A toolbar with a left group and a right group. Items at the start, items at the end, with the available space between.
- A grid of cards where each row is independent. The cards in a row align, but the rows are independent — the third card in the second row does not need to align with the third card in the first row.
Flexbox is not the right tool for two-dimensional layouts where rows and columns need to align together. That is what grid is for. The quick test: if your layout has a clear "main axis" (one row or one column), flexbox. If it has both and the items need to align across both, grid.
The six properties that matter
For most layouts, you only need these six properties. Memorize them.
display: flex
Turns the container into a flex container. Its direct children become flex items, and the rest of the layout (block flow, inline flow) is suspended for those children. This is the only mandatory declaration to start using flexbox.
flex-direction
Sets the main axis. The default is row (left to right). Other values are row-reverse (right to left), column (top to bottom), and column-reverse (bottom to top). The choice of direction changes which property controls the main axis vs. the cross axis (see below).
flex-wrap
Controls whether items wrap to a new line when there is not enough room. The default is nowrap, which is the source of the most common flexbox bug. Other values are wrap (items wrap to the next line) and wrap-reverse (items wrap to a new line above). For most responsive layouts, you want wrap.
justify-content
Distributes items along the main axis. Values: flex-start (default, items at the start), flex-end (items at the end), center (items centered), space-between (first item at start, last at end, equal space between), space-around (equal space around each item, half-size at the edges), space-evenly (equal space everywhere, including the edges). This is the property you reach for most often.
align-items
Aligns items along the cross axis. Values: stretch (default, items fill the cross-axis size), flex-start, flex-end, center, baseline (align by the text baseline, useful for rows of mixed-size text). This is the property people confuse with justify-content (see below).
gap
The space between items. The cleanest way to add spacing in flexbox. Replaces the old margin-right + :last-child { margin-right: 0; } hack. gap: 16px adds 16px between every adjacent pair of items, with no edge effect.
Justify-content vs. align-items: the most common confusion
These two properties are the source of half of all flexbox frustration. The rule:
justify-contentcontrols the main axis. The main axis is the direction set byflex-direction. If direction is row, main axis is horizontal. If direction is column, main axis is vertical.align-itemscontrols the cross axis. The cross axis is perpendicular to the main axis. If direction is row, cross axis is vertical. If direction is column, cross axis is horizontal.
For the default flex-direction: row:
justify-contentdistributes items left-to-right (or right-to-left, or centered, or with space between).align-itemsaligns items top-to-bottom (or bottom-to-top, or centered, or stretched to fill).
For a vertical column (flex-direction: column), the axes flip:
justify-contentdistributes items top-to-bottom.align-itemsaligns items left-to-right.
The mental model that works: "justify is along the direction; align is across the direction." This is the rule that disambiguates the two.
Common gotchas
1. Forgetting that flex children shrink by default
Each flex item has a default flex: 0 1 auto, which means "do not grow, shrink if needed, base size is the content size." A 200px-wide image inside a 300px container will shrink to fit. To prevent shrinking, use flex-shrink: 0 on the child. To force a specific size, set the child's width or flex-basis.
2. Mixing margin and gap
Using margin-right on flex children plus gap on the container produces double spacing. Pick one. For most cases, gap on the container is the cleaner option.
3. Centering a single item requires both justify and align
The classic "center a div in its parent" pattern. With flexbox, the parent is display: flex; justify-content: center; align-items: center;. Both properties are needed because flexbox is one-dimensional — you have to center on both axes separately.
4. Using flexbox for a grid
Flexbox is for one-dimensional layouts. If you need rows AND columns to align, use grid. The two are complementary, not interchangeable.
5. The flex shorthand is misleading
flex: 1 is shorthand for flex: 1 1 0%, which means "grow, shrink, base size 0". This is the right value for "items that share the available space equally". The full shorthand is flex: grow shrink basis. The default is flex: 0 1 auto.
A practical example: a centered login form
A common layout: a form centered both horizontally and vertically in the page. With flexbox, the parent is one declaration:
The HTML:
<div class="page">
<form class="login">...</form>
</div>
The CSS:
.page {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
That is the entire layout. The form is centered both ways, the page takes at least the full viewport height, and the layout is responsive by default.
Another example: a sticky-footer page
A page where the footer is at the bottom of the viewport when the content is short, and below the content when the content is long. The classic "sticky footer" pattern, with flexbox:
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1;
}
footer {
/* normal block flow */
}
The main element grows to fill the available space, pushing the footer to the bottom of the viewport on short pages and below the content on long pages. No JavaScript, no media queries, no magic numbers.
How to experiment without writing a full HTML file
The CSS Flexbox Playground on this site is an interactive editor. You write the CSS on the left, see the layout on the right, and the result updates live as you type. The playground comes with a few example layouts (row of items, centered form, sticky footer) so you can see what each property does, then modify the values to match your use case.
The advantage of the playground over a real stylesheet: you can change one property at a time, see exactly what each one does, and undo if you go down a wrong path. For learning flexbox or for prototyping a layout, the playground is faster than the edit-reload loop of a real stylesheet.
For the production stylesheet
Once you have the layout right in the playground, the same CSS goes into your stylesheet. The only difference is that real CSS lives in a file or a <style> block, not in a single-line playground input. The properties are the same, the values are the same, and the result is the same.
For the production site, the CSS Minifier takes the layout CSS (plus the rest of your stylesheet) and produces the minified version that ships to the browser. The minified version is functionally identical, just smaller.
A short checklist for new flexbox layouts
- Is this a one-dimensional layout (one row or one column)? If yes, flexbox. If no, grid.
- What is the main axis? Row (default) or column?
- How do items distribute along the main axis?
justify-content. - How do items align along the cross axis?
align-items. - Do items wrap when there is not enough room?
flex-wrap: wrapfor yes. - How much space between items?
gap, not margin.
Six properties. That is the entire flexbox vocabulary for most layouts. The rest is the same kind of layout thinking you would do for any design — but flexbox makes the implementation trivial.