Flexbox Basics
Navigation bars, rows of buttons, a card with an icon next to its text, a footer with links spread across it: these are all one-dimensional layouts, a row or a column of things. Flexbox is the CSS layout system built for exactly this. Before Flexbox, developers used floats and other tricks; today a few lines handle it, including the once-famous problem of centring something vertically.
In this lesson you will create a flex container and learn the properties you set on it: direction, wrapping, alignment along both axes, and spacing with gap. Properties set on the children, such as flex-grow, are covered in the next lesson, Flexbox Items.
Flex containers and flex items
Add display: flex to an element and it becomes a flex container. Its direct children become flex items and are laid out by Flexbox. Grandchildren are not affected; they stay in normal flow inside their own parent.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>First flex container</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; }
.site-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
padding: 0.75rem 1rem;
background: #1d3557;
color: white;
}
.site-header nav { display: flex; gap: 1rem; }
.site-header a { color: white; text-decoration: none; }
.logo { font-weight: bold; font-size: 1.25rem; }
</style>
</head>
<body>
<header class="site-header">
<span class="logo">Rohtak Sports</span>
<nav>
<a href="#">Cricket</a>
<a href="#">Football</a>
<a href="#">Contact</a>
</nav>
</header>
</body>
</html>The header has two flex items: the logo and the <nav>. justify-content: space-between pushes them to opposite ends, and align-items: center lines them up vertically. The <nav> is itself a flex container for its three links, with gap putting space between them. Nesting flex containers like this is completely normal.
Without any other properties, a flex container already does three useful things: it places items in a row, lets them shrink if space runs out, and stretches them to the same height.
Main axis and cross axis
Flexbox works along two axes:
- The main axis is the direction items are placed in. For a row, it runs along the line of text (left to right in English).
- The cross axis runs at right angles to it. For a row, that is top to bottom.
Every alignment property works on one of these axes. justify-content works on the main axis and align-items works on the cross axis. If you remember only one thing from this lesson, remember that pair.
flex-direction
flex-direction sets the main axis:
| Value | Items are placed |
|---|---|
row | In a row, in the direction of the text (default) |
row-reverse | In a row, in the opposite direction |
column | In a column, top to bottom |
column-reverse | In a column, bottom to top |
When you switch to column, the axes swap: now justify-content works vertically and align-items works horizontally.
justify-content: the main axis
justify-content decides what happens to spare space along the main axis.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>justify-content</title>
<style>
body { font-family: system-ui, sans-serif; padding: 1rem; }
.row { display: flex; background: #eef2f7; margin-block: 0.4rem 1rem; padding: 0.4rem; border-radius: 6px; }
.row span { background: oklch(55% 0.14 250); color: white; padding: 0.4rem 0.8rem; border-radius: 4px; }
code { font-size: 0.9rem; }
</style>
</head>
<body>
<code>flex-start</code>
<div class="row" style="justify-content: flex-start"><span>Tea</span><span>Coffee</span><span>Lassi</span></div>
<code>center</code>
<div class="row" style="justify-content: center"><span>Tea</span><span>Coffee</span><span>Lassi</span></div>
<code>flex-end</code>
<div class="row" style="justify-content: flex-end"><span>Tea</span><span>Coffee</span><span>Lassi</span></div>
<code>space-between</code>
<div class="row" style="justify-content: space-between"><span>Tea</span><span>Coffee</span><span>Lassi</span></div>
<code>space-around</code>
<div class="row" style="justify-content: space-around"><span>Tea</span><span>Coffee</span><span>Lassi</span></div>
<code>space-evenly</code>
<div class="row" style="justify-content: space-evenly"><span>Tea</span><span>Coffee</span><span>Lassi</span></div>
</body>
</html>The example uses inline style attributes only so each row can be compared side by side. The values mean:
flex-start(default): items packed at the start.center: items packed in the middle.flex-end: items packed at the end.space-between: first and last items touch the edges; equal space between the rest.space-around: equal space around each item, so the edges get half-size gaps.space-evenly: exactly equal gaps everywhere, including the edges.
align-items: the cross axis
align-items positions items along the cross axis, inside their line:
stretch(default): items stretch to fill the line's height. This is why cards in a flex row are equal height.flex-start/flex-end: items sit at the start or end of the cross axis.center: items are centred on the cross axis.baseline: items line up by the baseline of their first line of text, useful when items have different font sizes.
To align one item differently from the rest, you set align-self on that item; see Flexbox Items.
Centring anything
Centre a child both ways by combining the two properties:
.hero {
display: flex;
justify-content: center; /* main axis: horizontally */
align-items: center; /* cross axis: vertically */
min-height: 60svh; /* the container needs height to centre within */
}flex-wrap and gap
By default, flex items stay on one line, shrinking as much as they can, and then overflowing. flex-wrap: wrap lets them move onto new lines instead. gap sets the space between items, and between lines when they wrap. Use row-gap and column-gap to set the two separately.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>flex-wrap and gap</title>
<style>
body { font-family: system-ui, sans-serif; padding: 1rem; }
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 0.75rem; /* row-gap column-gap */
max-width: 22rem;
padding: 0.75rem;
border: 1px dashed #9aa8b8;
}
.tags a {
background: #e8eef7;
padding: 0.3rem 0.8rem;
border-radius: 999px;
text-decoration: none;
color: #1d3557;
}
</style>
</head>
<body>
<h3>Popular courses in Pune</h3>
<div class="tags">
<a href="#">Python</a><a href="#">Web design</a><a href="#">Tally</a>
<a href="#">Spoken English</a><a href="#">Data analysis</a><a href="#">Java</a>
<a href="#">Digital marketing</a><a href="#">Excel</a>
</div>
</body>
</html>The tags fill each line and wrap neatly onto the next, with consistent spacing between items and between lines. Change flex-wrap: wrap to nowrap and they squash into a single line and overflow the box.
flex-flow is a shorthand for flex-direction and flex-wrap together, such as flex-flow: row wrap.
align-content: lines in a wrapping container
When a container wraps onto several lines and has extra height, align-content decides how the lines are spread along the cross axis. It takes the same values as justify-content (flex-start, center, space-between and so on) plus stretch, the default.
.gallery {
display: flex;
flex-wrap: wrap;
align-content: flex-start; /* keep wrapped rows packed at the top */
min-height: 30rem;
gap: 1rem;
}align-content has no effect on a container that does not wrap. If you are aligning items on a single line, you want align-items.
Common mistakes
- Setting
display: flexon the wrong element. It goes on the parent; the children become the items. - Mixing up the axes.
justify-contentis the main axis,align-itemsis the cross axis. In a column they swap direction. - Vertical centring with no height. A container only as tall as its content has no space to centre in. Give it a
min-height. - Margins for spacing. Use
gap; it adds space only between items, never at the edges. - Using
align-contenton one line. It only works when items wrap onto several lines.
Key points
display: flexmakes an element a flex container and its direct children flex items.flex-directionsets the main axis:row(default) orcolumn, optionally reversed.justify-contentaligns items along the main axis;align-itemsaligns them on the cross axis.justify-content: centerplusalign-items: centercentres content in both directions.flex-wrap: wraplets items flow onto new lines, andgapspaces items and lines.align-contentspreads wrapped lines along the cross axis.
Exercise
Build a footer for a Jaipur travel agency. It should have three groups in a row: the agency name, a list of four links, and a phone number. Push the three groups apart, centre them vertically, and let them wrap onto new lines with a 1rem gap on narrow screens. Make the list of links a flex container too, with no bullets.
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Travel footer</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; }
footer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 1rem;
padding: 1.5rem 1rem;
background: #3a1f0f;
color: #fdf3e7;
}
footer ul { display: flex; flex-wrap: wrap; gap: 1rem; list-style: none; margin: 0; padding: 0; }
footer a { color: inherit; }
</style>
</head>
<body>
<footer>
<strong>Pink City Travels</strong>
<ul>
<li><a href="#">Tours</a></li>
<li><a href="#">Hotels</a></li>
<li><a href="#">Car rental</a></li>
<li><a href="#">Contact</a></li>
</ul>
<span>Call: 0141 000 0000</span>
</footer>
</body>
</html>space-between pushes the three groups apart on wide screens, and flex-wrap: wrap with gap stacks them neatly when space runs out.
Quick Quiz
1. Which elements become flex items when you set display: flex on a container?
Flexbox lays out the container's direct children; deeper elements are not flex items.
2. In a container with flex-direction: row, which property centres items vertically?
In a row the cross axis is vertical, and align-items works on the cross axis.
3. Which justify-content value gives exactly equal space between items and at both edges?
space-evenly makes every gap the same size, including the gaps at the edges.
4. What does flex-wrap: wrap do?
With wrapping on, items that do not fit start a new flex line instead of overflowing.
Learn CSS with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
