HTML and CSS course Β· Module 4: Flexbox
Flex-grow, Flex-shrink, Flex-basis - Precise Size Control
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. What does the flex-grow property do?
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: