Flexbox Items

CSS · Lesson 26 of 55 8 min read Updated

In Flexbox Basics you turned a parent into a flex container and arranged its children in a row or a column. This lesson is about the children themselves, the flex items. You will learn how they decide their size, how they share extra space, how they give space back when the row is too tight, and how to move or align a single item.

These properties are what make Flexbox feel flexible. Once you understand them, layouts like a search bar that fills the header or a footer that stays at the bottom of the page take only a few lines.

How flex items share space

Every time the browser lays out a flex container, it does a small calculation along the main axis (the direction of the row or column):

  1. It finds each item's starting size, called its flex basis.
  2. It adds up those sizes and compares the total with the container's size.
  3. If there is space left over, it hands that free space to items that are allowed to grow.
  4. If the items are too big, it takes space away from items that are allowed to shrink.

Three properties control this: flex-basis (the starting size), flex-grow (how much of the extra space an item takes) and flex-shrink (how much an item gives up when space is short).

flex-basis: the starting size

flex-basis sets an item's size along the main axis before any growing or shrinking happens. In a row, it acts like a width. In a column, it acts like a height.

CSS
.sidebar {
  flex-basis: 250px; /* start at 250px wide in a row */
}

.tag {
  flex-basis: auto; /* the default: use width, or the content size */
}

The default value auto means "look at the item's width (or height in a column), and if that is also auto, use the size of the content". This is why, by default, a short word makes a narrow item and a long sentence makes a wide one.

flex-grow: sharing extra space

flex-grow is a number that says how many shares of the free space an item takes. The default is 0, so items do not grow unless you ask them to. Run this example and compare the two rows.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>flex-grow</title>
  <style>
    body { font-family: system-ui, sans-serif; }
    .row {
      display: flex;
      gap: 8px;
      padding: 8px;
      margin-bottom: 12px;
      background: #eef2ff;
    }
    .row div {
      padding: 12px;
      background: #4338ca;
      color: white;
    }
    .grow-1 { flex-grow: 1; }
    .grow-2 { flex-grow: 2; }
  </style>
</head>
<body>
  <p>No flex-grow (the default):</p>
  <div class="row">
    <div>Tea</div>
    <div>Masala coffee</div>
    <div>Lassi</div>
  </div>
  <p>flex-grow 1, 2, 1:</p>
  <div class="row">
    <div class="grow-1">Tea</div>
    <div class="grow-2">Masala coffee</div>
    <div class="grow-1">Lassi</div>
  </div>
</body>
</html>

In the second row the free space is split into four shares: one for Tea, two for Masala coffee and one for Lassi. Notice that Masala coffee is not exactly twice as wide as Tea. It gets twice as much of the extra space, but it also started wider because its text is longer. If you want sizes in an exact ratio, set the basis to zero so that all of the space counts as free space. The flex shorthand below does exactly that.

flex-shrink: giving space back

When the items are wider than the container, flex-shrink decides who gets smaller. The default is 1, so every item shrinks a little. Items with a bigger basis give up more, so the shrinking feels fair.

Set flex-shrink: 0 on anything that must keep its size, such as a profile photo, a logo or an icon. Without it, a long piece of text next to the photo can squeeze the photo into a thin strip.

There is one surprise here. A flex item will not shrink below the width of its longest word or widest child, because flex items have min-width: auto by default. A long email address or URL can therefore push the whole row wider than the screen. The fix is min-width: 0 on the item that holds the text.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>flex-shrink and min-width</title>
  <style>
    body { font-family: system-ui, sans-serif; max-width: 360px; }
    .contact {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 8px;
    }
    .avatar {
      flex-shrink: 0;
      width: 48px;
      height: 48px;
      border-radius: 50%;
      background: #f59e0b;
    }
    .details {
      min-width: 0; /* allow the text box to shrink below its content */
    }
    .email {
      margin: 0;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
  </style>
</head>
<body>
  <div class="contact">
    <div class="avatar"></div>
    <div class="details">
      <strong>Ananya Iyer</strong>
      <p class="email">ananya.iyer.accounts.department@example-college.ac.in</p>
    </div>
  </div>
</body>
</html>

Delete the min-width: 0 line and run it again: the long email pushes the card wider than its box instead of ending with "...".

The flex shorthand

In real projects you rarely write the three properties separately. The flex shorthand sets flex-grow, flex-shrink and flex-basis in one go, and its keywords cover most needs.

You writeSame asUse it for
flex: 11 1 0Equal columns, whatever their content
flex: auto1 1 autoGrow, but keep content-based starting sizes
flex: none0 0 autoFixed items such as icons and buttons
flex: 0 0 240pxgrow 0, shrink 0, basis 240pxA fixed-width sidebar
flex: 1 1 200pxgrow and shrink from 200pxCards that wrap onto new lines

The default for every flex item is 0 1 auto: do not grow, may shrink, start from the content size.

The most common mix-up is between flex: 1 and flex: auto. With flex: 1 the basis is zero, so all items end up the same size even if one has much more text. With flex: auto each item starts from its content size, so longer items stay wider.

order and align-self

Two more properties work on a single item.

order moves an item visually. Every item starts with order: 0, and items are drawn from the lowest number to the highest. align-self overrides the container's align-items for one item only, which is handy when one item should sit at the bottom or the top of a row.

CSS
.featured {
  order: -1;          /* drawn before all items with order 0 */
}

.price-tag {
  align-self: flex-end; /* this item sits at the bottom of the row */
}

Common Flexbox patterns

A few item-level tricks solve everyday layout problems.

  • Push one item to the end: an auto margin soaks up all the free space, so margin-inline-start: auto on the last link pushes it to the right of a navigation bar.
  • A box that fills the rest: flex: 1 on a search input makes it take whatever space the logo and button leave.
  • Footer at the bottom: make the page a flex column with min-height: 100dvh and give the main content flex: 1.
  • Fixed plus flexible: flex: none on an image and flex: 1 with min-width: 0 on the text next to it.

This header uses the first two patterns.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Header patterns</title>
  <style>
    body { margin: 0; font-family: system-ui, sans-serif; }
    .header {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 12px 16px;
      background: #0f172a;
      color: white;
    }
    .logo { flex: none; font-weight: bold; }
    .search {
      flex: 1;
      min-width: 0;
      padding: 8px;
      border: 0;
      border-radius: 6px;
      font: inherit;
    }
    .login {
      margin-inline-start: auto;
      flex: none;
      color: #facc15;
    }
  </style>
</head>
<body>
  <header class="header">
    <span class="logo">Pune Books</span>
    <input class="search" type="search" placeholder="Search books" aria-label="Search books">
    <a class="login" href="#">Log in</a>
  </header>
</body>
</html>

The page-footer pattern looks like this in CSS:

CSS
body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  margin: 0;
}

main {
  flex: 1; /* main grows, so the footer is pushed to the bottom */
}

Common mistakes

  • Expecting flex-grow: 2 to mean "twice as wide". It means twice the extra space. Use flex: 2 and flex: 1 (basis zero) for exact ratios.
  • Text overflowing a flex item. Add min-width: 0 to the item, or min-height: 0 in a column, so it can shrink below its content.
  • Squashed images and icons. Give them flex: none or flex-shrink: 0.
  • Using order to fix the reading order. It only changes the visual order. Fix the HTML instead.

Key points

  • flex-basis is an item's starting size along the main axis; auto uses its width or content.
  • flex-grow shares out free space in proportion to each item's number; the default is 0.
  • flex-shrink decides who gets smaller when space is short; 0 keeps an item's size.
  • Use the flex shorthand: flex: 1 for equal items, flex: auto for content-based items, flex: none for fixed ones.
  • Flex items will not shrink below their content unless you set min-width: 0.
  • order and align-self affect one item, but order never changes the reading order.

Exercise

Build a row for a train ticket booking page with three items: a "From" box, a "To" box and a "Search trains" button. The two boxes should share the free space equally, whatever text is inside them, and the button should keep its natural size. Add a fourth item, a small "Swap" button, between the two boxes that never grows or shrinks.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Train search</title>
  <style>
    .search-row { display: flex; gap: 8px; }
    .place { flex: 1; min-width: 0; padding: 8px; }
    .swap, .go { flex: none; }
  </style>
</head>
<body>
  <div class="search-row">
    <input class="place" value="Rohtak Junction" aria-label="From">
    <button class="swap" type="button">Swap</button>
    <input class="place" value="Jaipur" aria-label="To">
    <button class="go" type="button">Search trains</button>
  </div>
</body>
</html>

flex: 1 gives both boxes a basis of zero, so they end up the same width. flex: none keeps both buttons at their content size, and min-width: 0 lets the inputs shrink on a narrow phone.

Quick Quiz

1. Three items have flex-grow values of 1, 1 and 2. What does the last item get?

2. What does flex: none mean?

3. A long URL inside a flex item makes the row wider than the screen. What is the usual fix?

4. Why should you be careful with the order property?

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