Lesson 7 of 12

CSS Flexbox

CSS Flexbox is a layout system for arranging items in one direction: a row or a column. It makes everyday tasks easy that used to need hacks, such as centring something vertically, spacing navigation links evenly or making cards in a row equal height. It is supported in every modern browser and is a core skill for any front-end developer.

Flex containers and flex items

CSS Flexbox works on two levels. You add display: flex to a parent, which becomes the flex container. Its direct children automatically become flex items and line up in a row. Grandchildren are not affected unless you make their parent a flex container too.

Flexbox thinks in two axes. The main axis is the direction items flow, set by flex-direction (row by default, or column). The cross axis runs at right angles to it. Almost every flex property aligns along one of these two axes, so knowing which is which is the key to Flexbox.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A navigation bar with Flexbox</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; }

.nav {
  display: flex;
  align-items: center;          /* cross axis: vertical centre */
  justify-content: space-between; /* main axis: spread out */
  gap: 16px;
  padding: 12px 20px;
  background: #102a43;
  color: white;
}

.nav ul {
  display: flex;
  gap: 20px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav a { color: white; text-decoration: none; }
</style>
</head>
<body>
<nav class="nav">
  <strong>Thanjavur Crafts</strong>
  <ul>
    <li><a href="#">Paintings</a></li>
    <li><a href="#">Dolls</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
</body>
</html>

Container properties

PropertyCommon valuesWhat it controls
flex-directionrow, columnThe direction of the main axis
justify-contentflex-start, center, space-between, space-evenlyAlignment and spacing along the main axis
align-itemsstretch, center, flex-start, baselineAlignment along the cross axis
flex-wrapnowrap, wrapWhether items may move onto new lines
gap16px, 1rem 2remSpace between items (not around the edges)

The default align-items: stretch is why flex items in a row become equal height: they all stretch to the tallest one. Use gap for spacing between items instead of margins. It never adds space at the outer edges and needs no “remove the margin on the last item” fixes.

Tip: Centring anything both ways takes three lines: display: flex; justify-content: center; align-items: center; on the parent. The parent needs some height for the vertical centring to be visible.

Item properties: grow, shrink and basis

Flex items can share space flexibly. Three properties control this, usually written together with the flex shorthand:

  • flex-grow: how much of the leftover space an item takes. 1 means “take an equal share”; 0 means “do not grow”.
  • flex-shrink: how much an item shrinks when there is not enough space. The default is 1.
  • flex-basis: the starting size before growing or shrinking, such as 200px or auto.

Common shorthands are flex: 1 (grow equally from a zero basis, so items end up the same width) and flex: 1 1 250px (start at 250px, then grow or shrink). An individual item can break alignment with align-self, and margin-inline-start: auto pushes an item to the far end of a row.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Wrapping cards that share space</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; padding: 20px; }

.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.card {
  flex: 1 1 220px;     /* at least about 220px, grow to fill */
  padding: 16px;
  border: 1px solid #d0d7de;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
}

.card button {
  margin-block-start: auto;   /* pushes button to the bottom */
  padding: 8px;
  font: inherit;
}
</style>
</head>
<body>
<div class="cards">
  <article class="card"><h3>Ooty</h3><p>Tea gardens and a toy train.</p><button>Explore</button></article>
  <article class="card"><h3>Coorg</h3><p>Coffee estates, waterfalls and misty hills with long walking trails.</p><button>Explore</button></article>
  <article class="card"><h3>Gokarna</h3><p>Quiet beaches.</p><button>Explore</button></article>
</div>
</body>
</html>

Resize the preview: the cards wrap onto new lines when there is no room for 220px each, with no media query needed. Each card is also a column flex container, so margin-block-start: auto pushes every button to the bottom and they line up neatly even when descriptions differ in length.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Perfect centring and push-to-end</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; }

.hero {
  min-height: 60vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #fff4e6;
}

.toolbar {
  display: flex;
  gap: 8px;
  padding: 12px;
  border-block-start: 1px solid #ddd;
}

.toolbar .logout { margin-inline-start: auto; }
</style>
</head>
<body>
<section class="hero"><h1>Centred in both directions</h1></section>
<div class="toolbar">
  <button>Save</button>
  <button>Share</button>
  <button class="logout">Log out</button>
</div>
</body>
</html>

Watch out: The order property and flex-direction: row-reverse change only the visual order. Keyboard users and screen readers still follow the HTML order, so a reversed layout can make tabbing jump around confusingly. Change the HTML if the logical order needs to change.

Debugging flex layouts

When a flex layout behaves strangely, check these points in order:

  1. Is display: flex on the parent, not on the items? Flex properties such as justify-content do nothing on an element that is not a flex container.
  2. Which way is the main axis? If you switched to flex-direction: column, justify-content and align-items swap jobs.
  3. Is an item refusing to shrink? Long words, URLs and images have a minimum content size. Adding min-width: 0 to the item lets it shrink below that size.
  4. Open developer tools. Chrome, Edge and Firefox show a “flex” badge next to flex containers that draws the items and gaps on the page.

When to use CSS Flexbox

Use Flexbox when content should flow in one direction and items decide their own size: navigation bars, toolbars, button groups, media objects (image beside text) and rows of tags. When you need to line things up in rows and columns at the same time, CSS Grid is usually the better tool. The two work well together, and the blog post Flexbox vs Grid compares them in depth.

Further reading

Key takeaways

  • display: flex makes a flex container; its direct children become flex items.
  • The main axis follows flex-direction; the cross axis runs across it.
  • justify-content aligns on the main axis, align-items on the cross axis.
  • Use gap for spacing and flex-wrap: wrap to let items move onto new lines.
  • The flex shorthand (grow, shrink, basis) controls how items share space.

Quick quiz

Check what you learned – pick an answer.

1. With flex-direction: column, which property centres items horizontally?

2. What does flex: 1 on every item in a row do?

3. Why is gap better than margins for spacing flex items?

Practice exercise

Build a footer with three items: a copyright line on the left and two links on the right. Use Flexbox so the links are pushed to the right, everything is vertically centred, and items wrap neatly on narrow screens with a 12px gap.

Show a hint

Use margin-inline-start: auto on the first link, or justify-content: space-between with the links grouped.

Show the solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Flex footer</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; }

footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 16px 20px;
  background: #f1f3f5;
}

footer .first-link { margin-inline-start: auto; }
</style>
</head>
<body>
<footer>
  <p>© 2026 Madurai Silks</p>
  <a class="first-link" href="#">Privacy</a>
  <a href="#">Contact</a>
</footer>
</body>
</html>

Progress is saved in this browser only.