CSS Flexbox Complete Guide
Flexbox is the layout model most developers reach for first, and for good reason. It handles the two problems that plagued CSS for years: distributing space along a line and aligning items that have different sizes. Once the mental model clicks, most everyday layouts stop being a fight.
The whole system rests on one idea: a flex container has two axes, and every property either controls spacing along one axis or alignment along the other. Get the axes straight and the rest follows.
The main axis and the cross axis
When you set display: flex on an element, it becomes a flex container and its direct children become flex items. The container has a main axis and a cross axis that runs perpendicular to it.
By default the main axis runs left to right (a row). The cross axis then runs top to bottom. The direction you choose decides which properties push items apart and which ones line them up. This is the single detail that trips people up, so keep it front of mind: justify-content works along the main axis, align-items works along the cross axis.
.container {
display: flex;
}Setting the direction
The flex-direction property decides where the main axis points. It accepts four values: row, row-reverse, column, and column-reverse. Switch to column and the axes swap: the main axis now runs top to bottom, so justify-content controls vertical spacing instead of horizontal.
.container {
display: flex;
flex-direction: column;
}This swap is why a justify-content: center rule can center things horizontally in one layout and vertically in another. Nothing changed in the property; the axis it points at changed.
justify-content vs align-items
These two are the workhorses, and they are easy to confuse. Think of them this way: justify-content distributes free space between items along the main axis, while align-items positions items across the cross axis.
.container {
display: flex;
justify-content: space-between;
align-items: center;
}Common justify-content values are flex-start, center, flex-end, space-between, space-around, and space-evenly. The three space values differ in how they handle the gaps at the edges: space-between puts no gap on the outside, space-around gives each item equal padding on both sides, and space-evenly makes every gap identical including the edges.
For align-items, the useful values are stretch (the default, items fill the cross axis), flex-start, center, flex-end, and baseline. Baseline is handy when items hold text of different sizes and you want the text to sit on a shared line.
Growing, shrinking, and the basis
Items are not fixed by default. The flex shorthand on each item controls how it responds when there is extra room or not enough. It bundles three values: flex-grow, flex-shrink, and flex-basis.
flex-grow decides how leftover space is shared. A value of 0 means do not grow. If one item has 1 and another has 2, the second takes twice the extra space. flex-shrink works in reverse: when items overflow, it decides who gives up space. flex-basis sets the starting size before growing or shrinking kicks in.
.sidebar {
flex: 0 0 240px;
}
.content {
flex: 1 1 auto;
}That pair is a classic sidebar layout: the sidebar holds a fixed 240px and refuses to grow or shrink, while the content area takes everything that remains. Writing flex: 1 on its own is shorthand for 1 1 0%, which is why a row of equal columns is often just flex: 1 on each.
Wrapping and gaps
By default flex items stay on one line even if they overflow. Add flex-wrap: wrap and items that no longer fit drop to the next line. Combined with flex-basis, this gives responsive grids without media queries.
.gallery {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.gallery > * {
flex: 1 1 200px;
}Each card wants at least 200px and grows to fill the row. When the row runs out of space, cards wrap. The gap property adds consistent spacing between items without the old margin tricks, and it applies both between columns and between wrapped rows.
Real layouts
A navbar is the canonical flexbox example. Put the logo on the left and the links on the right with one line:
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 24px;
}The logo and the link group sit at opposite ends because space-between pushes the free space between them, and align-items: center keeps everything on the same vertical line regardless of height.
Centering a card dead center in a container is the other request everyone has. Flexbox makes it two lines once you remember the axis rule:
.screen {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}Because the container is a default row, justify-content centers horizontally and align-items centers vertically. The old days of negative margins and absolute positioning for centering are gone.
Where to go next
Flexbox is built for one-dimensional layouts, a row or a column. When you need rows and columns to line up together as a true grid, CSS Grid is the better tool. The two work well side by side: Grid for the page skeleton, Flexbox for the components inside each cell.
The fastest way to internalize the axis behavior is to change values and watch items move. Pick a container, set display: flex, and tweak one property at a time until the model feels obvious.
Related tools: