HTML and CSS course Β· Module 4: Flexbox

Flex-grow, Flex-shrink, Flex-basis - Precise Size Control

10 min read Β·
In this lesson7

Welcome back to the Library of Alexandria! Three scrolls lie on one shelf: the first always needs the same amount of space, the second may take whatever is left, and the third gives way when things get tight, just like a menu, content and a side panel on a web page. These decisions are made by flex-basis, flex-grow and flex-shrink.

Flex-basis - Initial Element Size

flex-basis sets the initial size of an element BEFORE the free space is distributed. It accepts pixels, percentages, zero or auto:

.item {
  flex-basis: 200px;  /* Initial size 200px */
}

.item {
  flex-basis: 0;  /* Ignore content size, start from 0 */
}

.item {
  flex-basis: auto;  /* Use content size (default) */
}

.item {
  flex-basis: 50%;  /* 50% of container */
}

Zero tells the browser to ignore the content size. The default auto takes the element's width or, if there is none, the size of its content. So how does flex-basis differ from width?

/* Outside flexbox, width is rigid */
.item {
  width: 200px;  /* Outside flexbox: always 200px */
}

/* Flex-basis is a suggestion */
.item {
  flex-basis: 200px;  /* About 200px, but can grow/shrink */
}

Outside flexbox, width: 200px always means 200 pixels. In a flex container both values are only a starting point: with flex-basis: auto the browser takes width, and when you set both, flex-basis wins. It is like a stone block before carving, which can still be made larger or smaller.

Flex-grow - Element Growth

flex-grow defines how much an element can grow relative to the others when free space is left:

.container {
  display: flex;
  width: 600px;
}

.item-1 {
  flex-grow: 1;  /* Will take 1 share of free space */
  flex-basis: 100px;
}

.item-2 {
  flex-grow: 2;  /* Will take 2 shares of free space */
  flex-basis: 100px;
}

.item-3 {
  flex-grow: 1;  /* Will take 1 share of free space */
  flex-basis: 100px;
}

/* Free space: 600px - 300px = 300px
   Sum of flex-grow: 1 + 2 + 1 = 4

   item-1: 100px + (300px x 1/4) = 175px
   item-2: 100px + (300px x 2/4) = 250px
   item-3: 100px + (300px x 1/4) = 175px
*/

The browser splits the free 300 pixels into four parts, because that is the sum of the flex-grow values. Careful: flex-grow: 2 does not make an element twice as big, it only gives it twice as big a slice of the free space. The default flex-grow: 0 means no growth, 1 proportional growth, and 2 or 3 a share two or three times bigger. Usually only the content between the panels grows:

.layout {
  display: flex;
}

.sidebar {
  flex-grow: 0;  /* Sidebar does NOT grow */
  flex-basis: 250px;  /* Fixed size 250px */
}

.main-content {
  flex-grow: 1;  /* Main content takes all remaining space */
}

.aside {
  flex-grow: 0;  /* Aside does NOT grow */
  flex-basis: 200px;
}

The menu and the panel keep 250 and 200 pixels, and the content with flex-grow: 1 takes all the rest.

Flex-shrink - Element Shrinking

flex-shrink works the other way round: it defines how much an element can shrink when space runs out. The default value is 1:

.item {
  flex-shrink: 1;  /* Element can shrink (default) */
}

.item-important {
  flex-shrink: 0;  /* Element does NOT shrink */
}

.item-flexible {
  flex-shrink: 3;  /* Element shrinks 3x faster than others */
}

Zero turns shrinking off, and a bigger number means a bigger share in giving up space. Let's check it in a container that is 200 pixels short:

.container {
  display: flex;
  width: 400px;
}

.item-1 {
  flex-basis: 200px;
  flex-shrink: 1;  /* Shrinks normally */
}

.item-2 {
  flex-basis: 200px;
  flex-shrink: 2;  /* Shrinks 2x faster */
}

.item-3 {
  flex-basis: 200px;
  flex-shrink: 0;  /* Does NOT shrink */
}

/* Total: 600px, but container is only 400px
   Missing: 200px

   item-3 will remain 200px (flex-shrink: 0)
   item-1 and item-2 will share shrinking proportionally
*/

The third element stays at 200 pixels, and the first two give up the missing 200 in a 1 to 2 ratio: the first shrinks to about 133 pixels, the second to about 67. When shrinking, flex-basis counts too, so bigger elements give up more. Most often flex-shrink protects elements that must not get squashed, like a logo:

.header-logo {
  flex-shrink: 0;  /* Logo NEVER shrinks */
  width: 150px;
}

.header-nav {
  flex-shrink: 1;  /* Navigation can shrink */
}

.header-search {
  flex-shrink: 2;  /* Search bar shrinks fastest */
}

The logo is always 150 pixels wide, and when things get tight, the search box with flex-shrink: 2 gives up space more readily than the navigation.

Flex Shorthand - Combining All Three

From the previous lesson you know the flex shorthand, which combines all three values in the grow, shrink, basis order:

/* flex: grow shrink basis */
.item {
  flex: 1 1 200px;
  /* flex-grow: 1, flex-shrink: 1, flex-basis: 200px */
}

In the same way, flex: 1 0 200px means flex-grow: 1, flex-shrink: 0 and flex-basis: 200px.

Most Common Flex Values:

In everyday work, a few ready-made forms are enough, and they are worth knowing by heart:

/* flex: 1 - flexible element */
.item {
  flex: 1;
  /* Equivalent to: flex: 1 1 0 */
  /* Grow, shrink, start from 0 */
}

/* flex: auto - natural size with flexibility */
.item {
  flex: auto;
  /* Equivalent to: flex: 1 1 auto */
  /* Grow, shrink, start from content size */
}

/* flex: none - rigid size */
.item {
  flex: none;
  /* Equivalent to: flex: 0 0 auto */
  /* Do NOT grow, do NOT shrink */
}

/* flex: 0 0 200px - absolutely rigid */
.item {
  flex: 0 0 200px;
  /* Always 200px, no growing/shrinking */
}

/* flex: 2 - grow 2x faster */
.item {
  flex: 2;
  /* Equivalent to: flex: 2 1 0 */
}

flex: 1 starts from zero, so several such elements share the space equally, while flex: auto starts from the content size, so a longer text gets a wider column. My advice: for equal columns, choose flex: 1.

Practical Examples

1. Dashboard layout - 3 columns

The first layout is an admin panel with a menu, content and widgets:

<div class="dashboard">
  <aside class="sidebar">Sidebar (fixed)</aside>
  <main class="main-content">Main (flexible)</main>
  <aside class="widgets">Widgets (fixed)</aside>
</div>

The menu gets a rigid flex: 0 0 250px, the content flex: 1, and the panel flex: 0 1 300px, which means it prefers 300 pixels but can give way:

.dashboard {
  display: flex;
  gap: 20px;
  height: 100vh;
}

.sidebar {
  flex: 0 0 250px;  /* Fixed: 250px */
  background: #34495e;
}

.main-content {
  flex: 1;  /* Takes all remaining space */
  background: white;
  overflow-y: auto;
}

.widgets {
  flex: 0 1 300px;  /* Preferred: 300px, can shrink */
  background: #ecf0f1;
}

/* On small screens */
@media (max-width: 768px) {
  .dashboard {
    flex-direction: column;
  }

  .sidebar,
  .widgets {
    flex: 0 0 auto;  /* Automatic size */
  }
}

On a phone, the media query stacks the columns on top of each other and gives the panels back their natural size with flex: 0 0 auto.

2. Responsive header

The second example is a header with a logo, navigation, a search box and a user account:

<header class="header">
  <div class="logo">Logo</div>
  <nav class="nav">Navigation</nav>
  <div class="search">Search</div>
  <div class="user">User</div>
</header>

Notice min-width: 0 on the navigation and min-width: 150px on the search box, which we will come back to while debugging:

.header {
  display: flex;
  gap: 20px;
  padding: 10px 20px;
  background: #2c3e50;
  align-items: center;
}

.logo {
  flex: 0 0 150px;  /* Always 150px */
}

.nav {
  flex: 1 1 auto;  /* Takes available space */
  min-width: 0;  /* Important for shrinking */
}

.search {
  flex: 0 1 300px;  /* Prefers 300px, can shrink */
  min-width: 150px;  /* Minimum 150px */
}

.user {
  flex: 0 0 100px;  /* Always 100px */
}

The navigation takes the free space, and the search box prefers 300 pixels but will not go below 150.

3. Card grid with different sizes

The third example is a grid of cards in three sizes:

<div class="card-grid">
  <div class="card small">Small</div>
  <div class="card medium">Medium</div>
  <div class="card large">Large</div>
  <div class="card small">Small</div>
</div>

The container wraps the cards thanks to flex-wrap: wrap, the flex-flow: row wrap from the previous lesson. Small cards take a quarter of the width minus part of the gap, medium ones half, and large ones a whole row:

.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

.card {
  height: 200px;
  background: #3498db;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card.small {
  flex: 0 0 calc(25% - 15px);  /* 1/4 width minus gap */
}

.card.medium {
  flex: 0 0 calc(50% - 10px);  /* 1/2 width minus gap */
}

.card.large {
  flex: 0 0 100%;  /* Full width */
}

@media (max-width: 768px) {
  .card.small,
  .card.medium {
    flex: 0 0 100%;  /* Full width on mobile */
  }
}

Four small cards would fill a row to the pixel, because four times calc(25% - 15px) plus three gaps of 20 pixels adds up to 100%.

Debugging Flexbox

Problem 1: Does width block growing?

Many beginners believe that width combined with flex-grow blocks growing. Here is such code and two popular remedies:

/* Problem */
.item {
  flex-grow: 1;
  width: 200px;  /* Only a starting point */
}

/* Solution */
.item {
  flex: 1;  /* flex automatically overrides width */
  /* or */
  flex-grow: 1;
  min-width: 200px;  /* Use min-width instead of width */
}

It is a myth: in a container 600 pixels wide, two such elements get 300 pixels each, because width is only a starting point. Trouble starts when neighbours have different widths, because each of them starts from a different place, and flex: 1 evens out that start. If an element really does not grow, check its flex-grow, its max-width and whether its parent has display: flex.

Problem 2: Element does not shrink

This problem is real: an element with flex-shrink: 1 stubbornly keeps its width:

/* Problem */
.item {
  flex-shrink: 1;
  min-width: 300px;  /* min-width prevents shrinking! */
}

/* Solution */
.item {
  flex-shrink: 1;
  min-width: 0;  /* Allow shrinking */
}

The culprit is min-width. Flex items have min-width: auto by default, so they do not shrink below their longest unbreakable content, such as a URL.

Problem 3: Text overflows the container

That default value causes the third problem, a long text pushing the element out of its container:

/* Problem */
.item {
  flex: 1;
  /* Long text can push the element outside the container */
}

/* Solution */
.item {
  flex: 1;
  min-width: 0;  /* Crucial! */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

min-width: 0 lets the element shrink, overflow: hidden cuts off the excess, and text-overflow: ellipsis adds an ellipsis to text kept on a single line.

Summary

flex-basis is the flexible counterpart of width, flex-grow with its default 0 decides about growing, and flex-shrink with its default 1 about shrinking. The flex shorthand combines all three. In the next lesson you will build a whole column grid from these building blocks.

In the editor below you will find a demo of spacing that we will return to with gap. Add the rule .flex-item:first-child { flex-grow: 1; } and watch the first element take the free space from its neighbours.

Code for this lesson: index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flexbox - Gap</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>↔Gap - Spacing Between Elements</h1>
        <p class="subtitle">Modern way to create spacing in flexbox</p>

        <section class="demo-section">
            <h2>Without gap</h2>
            <div class="flex-container no-gap">
                <div class="flex-item">1</div>
                <div class="flex-item">2</div>
                <div class="flex-item">3</div>
                <div class="flex-item">4</div>
            </div>
            <p class="description">Elements without spacing</p>
        </section>

        <section class="demo-section">
            <h2>gap: 10px</h2>
            <div class="flex-container gap-10">
                <div class="flex-item">1</div>
                <div class="flex-item">2</div>
                <div class="flex-item">3</div>
                <div class="flex-item">4</div>
            </div>
            <p class="description">Small gap between all elements</p>
        </section>

        <section class="demo-section">
            <h2>gap: 30px</h2>
            <div class="flex-container gap-30">
                <div class="flex-item">1</div>
                <div class="flex-item">2</div>
                <div class="flex-item">3</div>
                <div class="flex-item">4</div>
            </div>
            <p class="description">Large gap between elements</p>
        </section>

        <section class="demo-section">
            <h2>row-gap and column-gap separately</h2>
            <div class="flex-container custom-gap">
                <div class="flex-item">1</div>
                <div class="flex-item">2</div>
                <div class="flex-item">3</div>
                <div class="flex-item">4</div>
                <div class="flex-item">5</div>
                <div class="flex-item">6</div>
            </div>
            <p class="description">row-gap: 40px, column-gap: 10px</p>
        </section>

        <section class="demo-section practice">
            <h2>Practice: Egyptian Senet board</h2>
            <p class="practice-description">Senet - the oldest board game from Egypt</p>

            <div class="board-container">
                <div class="senet-board">
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                    <div class="square empty"></div>
                    <div class="square">●</div>
                    <div class="square">●</div>
                </div>
            </div>

            <div class="game-info">
                <h3>Facts about Senet:</h3>
                <ul>
                    <li>The oldest known board game (c. 3100 BCE)</li>
                    <li>Game for 2 players</li>
                    <li>Board of 3x10 fields</li>
                    <li>A favorite game of the pharaohs</li>
                    <li>Found in Egyptian tombs</li>
                </ul>
            </div>
        </section>
    </div>
</body>
</html>

Remember: flex-grow, flex-shrink and flex-basis are the pharaoh's orders for the pyramid builders, telling them which blocks should grow, which should shrink and which must stay untouched.

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What does the flex-grow property do?

  2. 2. The shorthand property flex: 1 0 200px corresponds to which set of values?

Hands-on tasks in the game

  • Vertical ordering

    Arrange flex-grow values from least to most growth:

  • Horizontal ordering

    Arrange the shorthand flex-flow setting horizontal direction with element wrapping:

  • Click in order

    Arrange the elements to create a valid flex-basis declaration:

  • Horizontal ordering

    Arrange the order of values in the flex shorthand property:

Useful articles