Flexbox Item Properties
Introduction to Flex Item Properties
In previous lessons, you learned about flex container properties like display: flex, flex-direction, justify-content, and align-items. Those properties control the container and affect all children as a group. But Flexbox also gives you powerful properties that you apply directly to individual flex items, allowing you to control how each child grows, shrinks, sets its initial size, reorders itself, and aligns independently within the container. Mastering these item-level properties is the key to unlocking the full power of Flexbox and building truly flexible, responsive layouts.
In this lesson, we will cover every flex item property in depth: flex-grow, flex-shrink, flex-basis, the flex shorthand, order, and align-self. We will also walk through the flex sizing algorithm step by step, explore common pitfalls like the min-width: 0 overflow problem, learn the margin: auto trick, and build practical layouts including the holy grail layout, a sticky footer, and media objects.
flex-grow: Proportional Growth
The flex-grow property defines how much a flex item should grow relative to the other flex items when there is extra space available in the container. The default value is 0, which means items will not grow beyond their natural content size. When you set flex-grow to a positive number, the item will absorb a proportional share of the leftover space.
Example: Basic flex-grow
.container {
display: flex;
width: 600px;
}
.item-a {
flex-grow: 1; /* Gets 1 share of extra space */
width: 100px;
}
.item-b {
flex-grow: 2; /* Gets 2 shares of extra space */
width: 100px;
}
.item-c {
flex-grow: 1; /* Gets 1 share of extra space */
width: 100px;
}
Let us do the math. The container is 600px wide. The three items have a combined natural width of 300px (100px each). That leaves 300px of extra space. The total grow factor is 1 + 2 + 1 = 4. Item A gets 300px * (1/4) = 75px extra, making it 175px. Item B gets 300px * (2/4) = 150px extra, making it 250px. Item C gets 300px * (1/4) = 75px extra, making it 175px. The total is 175 + 250 + 175 = 600px, filling the container perfectly.
flex-grow value is not a percentage or a fixed size -- it is a ratio. flex-grow: 2 does not mean the item will be twice as wide as other items. It means the item receives twice the share of available extra space compared to items with flex-grow: 1.Example: Making All Items Grow Equally
.container {
display: flex;
}
/* All items share extra space equally */
.item {
flex-grow: 1;
}
/* Give one item more space than the others */
.item-featured {
flex-grow: 3;
}
flex-shrink: Controlling Shrinkage
The flex-shrink property defines how much a flex item should shrink relative to the other flex items when there is not enough space in the container. The default value is 1, which means all flex items will shrink equally to prevent overflow. Setting flex-shrink: 0 prevents an item from shrinking at all, which is useful for elements like sidebars or icons that should maintain a fixed size.
Example: Preventing Shrinkage
.container {
display: flex;
width: 500px;
}
.sidebar {
flex-shrink: 0; /* Will NOT shrink -- stays at 200px */
width: 200px;
}
.content {
flex-shrink: 1; /* Will shrink if needed */
width: 400px;
}
In this example, the combined natural width of the items is 600px, but the container is only 500px. There is a 100px deficit. Because the sidebar has flex-shrink: 0, it refuses to shrink. The content area absorbs the entire 100px deficit, shrinking from 400px to 300px. This pattern is extremely common for layouts where a sidebar must maintain a minimum width.
Example: Proportional Shrinking
.container {
display: flex;
width: 400px;
}
.item-a {
flex-shrink: 1;
width: 200px;
}
.item-b {
flex-shrink: 3;
width: 200px;
}
/* Deficit: 400px needed, 400px available = 0... but if container is 300px:
Deficit = 100px
Total shrink factor = 1*200 + 3*200 = 800
Item A shrinks: 100 * (1*200/800) = 25px -> becomes 175px
Item B shrinks: 100 * (3*200/800) = 75px -> becomes 125px */
flex-shrink: 1 and a 400px basis will shrink more in absolute pixels than an item with flex-shrink: 1 and a 100px basis, because the shrink factor is multiplied by the basis before distributing the deficit.flex-basis: The Initial Size
The flex-basis property sets the initial main size of a flex item before any growing or shrinking is applied. It determines the starting point from which flex-grow adds space or flex-shrink removes space. The default value is auto, which means the item uses its width (or height in a column layout) as the basis. If no width is set and the basis is auto, the item sizes to its content.
Example: flex-basis vs width
/* Using flex-basis (preferred in flex layouts) */
.item {
flex-basis: 200px;
}
/* Using width (works but flex-basis takes priority) */
.item {
width: 200px;
}
/* flex-basis overrides width in flex containers */
.item {
width: 300px;
flex-basis: 200px; /* This wins -- item starts at 200px */
}
/* auto means "look at my width property" */
.item {
width: 300px;
flex-basis: auto; /* Uses 300px from width */
}
/* content means "size to my content" (regardless of width) */
.item {
width: 300px;
flex-basis: content; /* Ignores 300px, sizes to content */
}
flex-basis with width. In a flex row, flex-basis controls the main axis size and takes priority over width. In a flex column, flex-basis controls height and takes priority over height. Always use flex-basis instead of width/height when you want the value to participate in the flex algorithm.flex-basis: 0 vs flex-basis: auto
The difference between flex-basis: 0 and flex-basis: auto is crucial and often misunderstood. With flex-basis: auto, the item starts at its natural content size (or explicit width), and then flex-grow distributes leftover space. With flex-basis: 0, the item starts at zero width, and flex-grow distributes all the container space proportionally. This means flex-grow: 1 with flex-basis: 0 gives you truly equal-width items, while flex-grow: 1 with flex-basis: auto gives you items that differ based on their content size.
Example: flex-basis: 0 for Equal Widths
/* Items have different content but equal widths */
.equal-items {
display: flex;
}
.equal-items .item {
flex-grow: 1;
flex-basis: 0;
/* All items will be exactly the same width regardless of content */
}
/* Items share extra space but start from content size */
.auto-items {
display: flex;
}
.auto-items .item {
flex-grow: 1;
flex-basis: auto;
/* Items with more content will be wider */
}
The flex Shorthand Property
The flex shorthand combines flex-grow, flex-shrink, and flex-basis into a single declaration. Using the shorthand is strongly recommended because it sets sensible defaults that differ from the individual property defaults. The syntax is: flex: <grow> <shrink> <basis>.
Example: flex Shorthand Values
/* flex: grow shrink basis */
.item {
flex: 1 1 200px;
/* flex-grow: 1, flex-shrink: 1, flex-basis: 200px */
}
/* Common shorthand patterns */
.item { flex: 1; }
/* Equivalent to: flex: 1 1 0% */
/* Item grows and shrinks equally, starts from zero width */
.item { flex: auto; }
/* Equivalent to: flex: 1 1 auto */
/* Item grows and shrinks, starts from content/width size */
.item { flex: none; }
/* Equivalent to: flex: 0 0 auto */
/* Item does NOT grow or shrink -- completely rigid */
.item { flex: 0 auto; }
/* Equivalent to: flex: 0 1 auto (same as initial) */
/* Item does not grow, can shrink, starts from content size */
/* Fixed size item that does not flex */
.item { flex: 0 0 250px; }
/* Does not grow, does not shrink, always 250px */
/* Two-value syntax */
.item { flex: 2 0; }
/* flex-grow: 2, flex-shrink: 0, flex-basis: 0% (unitless = grow shrink) */
.item { flex: 1 200px; }
/* flex-grow: 1, flex-shrink: 1, flex-basis: 200px (number + length) */
flex: 1, the flex-basis is set to 0%, NOT auto. This is different from writing flex-grow: 1 alone, which leaves flex-basis at its default of auto. This subtle difference is one of the most common sources of confusion in Flexbox. Always use the shorthand to avoid unexpected behavior.Which flex Value Should You Use?
flex: 1-- Use when you want items to fill the container equally. Best for equal-width columns, navigation items, or any situation where items should share all available space proportionally.flex: auto-- Use when you want items to grow and shrink but start from their natural content size. Good for navigation bars where each link text has different lengths.flex: none-- Use for items that should remain a fixed size. Perfect for icons, logos, avatars, or fixed-width sidebars.flex: 0 0 <size>-- Use when you want an exact size with no flexibility. Common for sidebar widths likeflex: 0 0 250px.
The order Property
The order property controls the visual order of flex items without changing the HTML source order. By default, all items have order: 0 and appear in source order. Items with lower order values appear first; items with higher order values appear later. Items with the same order value maintain their source order relative to each other.
Example: Reordering Items Visually
<div class="container">
<div class="item" style="order: 3">First in HTML</div>
<div class="item" style="order: 1">Second in HTML</div>
<div class="item" style="order: 2">Third in HTML</div>
</div>
/* Visual order: Second in HTML, Third in HTML, First in HTML */
Example: Moving One Item to the End
.container {
display: flex;
}
/* All items default to order: 0 */
.item-last {
order: 1; /* Moves to the end because all others are 0 */
}
/* Negative values move items to the beginning */
.item-first {
order: -1; /* Moves to the very beginning */
}
order property only changes visual order, not the tab order or screen reader order. Keyboard users will still tab through items in source order. This can create a confusing disconnect between what users see and how they navigate. Use order sparingly, and only when the visual reordering does not compromise the logical reading order for keyboard and screen reader users.align-self: Individual Alignment
The align-self property allows a single flex item to override the align-items value set on its container. This lets you align one specific item differently from the rest. It accepts the same values as align-items: auto, flex-start, flex-end, center, baseline, and stretch.
Example: Overriding Container Alignment
.container {
display: flex;
align-items: flex-start; /* All items align to the top */
height: 300px;
}
.item-centered {
align-self: center; /* This item centers vertically */
}
.item-bottom {
align-self: flex-end; /* This item goes to the bottom */
}
.item-stretched {
align-self: stretch; /* This item stretches full height */
}
Example: Practical Use -- Feature Card Highlight
.feature-cards {
display: flex;
align-items: flex-start;
gap: 20px;
}
.feature-card {
flex: 1;
padding: 20px;
background: var(--bg-white);
border-radius: 8px;
}
/* Make the highlighted card stretch full height */
.feature-card.highlighted {
align-self: stretch;
background: var(--primary-light);
border: 2px solid var(--primary);
}
The Flex Sizing Algorithm Step by Step
Understanding how the browser calculates flex item sizes is essential for debugging layouts and predicting behavior. Here is the complete algorithm, broken down into clear steps:
- Determine the flex basis -- For each item, the browser determines its hypothetical main size. If
flex-basisis a length (e.g., 200px), use that. Ifflex-basisisauto, use the item'swidth/height. If neither is set, size to content. - Sum the flex bases -- Add up all the hypothetical main sizes of every flex item in the line.
- Compare to the container -- If the total flex bases are less than the container's main size, there is positive free space (items will grow). If the total is greater, there is negative free space (items will shrink).
- Distribute positive free space -- If there is extra space, multiply each item's
flex-growfactor by its proportion of the total grow factors, then add that amount to the item's basis. - Distribute negative free space -- If there is insufficient space, multiply each item's
flex-shrinkfactor by its flex basis (this weighting is important), then remove a proportional amount from the item's basis. - Clamp to min/max -- After growth or shrinkage, clamp each item to its
min-width/max-width(ormin-height/max-heightin column layouts). If an item is clamped, freeze it and redistribute the remaining space among unfrozen items. - Repeat if needed -- If any items were frozen in step 6, recalculate the distribution of free space among the remaining flexible items. This continues until all space is distributed or all items are frozen.
Example: Algorithm Walkthrough
.container {
display: flex;
width: 800px;
}
.item-a { flex: 2 1 100px; } /* grow:2, shrink:1, basis:100px */
.item-b { flex: 1 1 200px; } /* grow:1, shrink:1, basis:200px */
.item-c { flex: 1 2 100px; } /* grow:1, shrink:2, basis:100px */
/* Step 1: Bases = 100 + 200 + 100 = 400px */
/* Step 2: Container = 800px */
/* Step 3: Free space = 800 - 400 = 400px (positive) */
/* Step 4: Total grow = 2 + 1 + 1 = 4 */
/* Item A: 100 + (400 * 2/4) = 100 + 200 = 300px */
/* Item B: 200 + (400 * 1/4) = 200 + 100 = 300px */
/* Item C: 100 + (400 * 1/4) = 100 + 100 = 200px */
/* Final: 300 + 300 + 200 = 800px */
The min-width: 0 Overflow Fix
One of the most frustrating Flexbox gotchas is unexpected overflow. By default, flex items have min-width: auto, which means they will never shrink smaller than their minimum content size. This causes long words, URLs, or non-wrapping content to force the item to overflow its container. The fix is simple: set min-width: 0 on the flex item.
Example: The Overflow Problem and Fix
/* THE PROBLEM */
.container {
display: flex;
width: 300px;
}
.item {
flex: 1;
/* A long URL or word inside this item will prevent shrinking */
/* The item overflows the container! */
}
/* THE FIX */
.item {
flex: 1;
min-width: 0; /* Allow shrinking below content size */
overflow: hidden; /* Or overflow: auto, text-overflow: ellipsis */
}
/* Common pattern for text truncation in flex items */
.text-truncate-flex {
flex: 1;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
min-height: auto in column flex layouts. Apply min-height: 0 to flex items in column containers if content is overflowing vertically. This is especially common with scrollable areas inside flex layouts.The margin: auto Trick in Flexbox
In Flexbox, margin: auto has a superpower: it absorbs all available free space in the direction of the auto margin. This is different from block layout where margin: 0 auto only centers horizontally. In flex containers, auto margins can push items in any direction and are incredibly useful for creating common patterns.
Example: Push Item to the Right
/* Navigation with logo on left, links on right */
.navbar {
display: flex;
align-items: center;
padding: 10px 20px;
}
.logo {
/* Stays on the left naturally */
}
.nav-links {
margin-left: auto; /* Pushes to the far right */
display: flex;
gap: 20px;
}
Example: Perfect Centering with margin: auto
/* Center a single item both horizontally and vertically */
.container {
display: flex;
height: 100vh;
}
.centered-item {
margin: auto;
/* Absorbs all space equally on all sides = perfect center */
}
Example: Push Footer to Bottom of Card
.card {
display: flex;
flex-direction: column;
height: 350px;
}
.card-header { /* Natural size */ }
.card-body { /* Natural size */ }
.card-footer {
margin-top: auto; /* Pushes to the bottom of the card */
}
justify-content and align-self have no effect on that item because the auto margins absorb all the free space before those properties get a chance to distribute it. Auto margins take priority over alignment properties.Practical Example: The Holy Grail Layout
The holy grail layout is a classic web design pattern with a header, footer, and three columns (left sidebar, main content, right sidebar). It was notoriously difficult to achieve with floats, but Flexbox makes it straightforward.
Example: Holy Grail Layout with Flex Item Properties
<div class="holy-grail">
<header class="hg-header">Header</header>
<div class="hg-body">
<nav class="hg-nav">Left Sidebar</nav>
<main class="hg-content">Main Content</main>
<aside class="hg-aside">Right Sidebar</aside>
</div>
<footer class="hg-footer">Footer</footer>
</div>
CSS for Holy Grail Layout
.holy-grail {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.hg-header, .hg-footer {
flex: none; /* flex: 0 0 auto -- fixed size */
padding: 20px;
background: var(--primary);
color: white;
}
.hg-body {
display: flex;
flex: 1; /* flex: 1 1 0% -- grows to fill remaining space */
}
.hg-nav {
flex: 0 0 200px; /* Fixed 200px sidebar */
padding: 20px;
background: var(--bg-light);
}
.hg-content {
flex: 1; /* Takes all remaining space */
padding: 20px;
min-width: 0; /* Prevent overflow */
}
.hg-aside {
flex: 0 0 180px; /* Fixed 180px sidebar */
padding: 20px;
background: var(--bg-light);
}
/* Responsive: stack on mobile */
@media (max-width: 768px) {
.hg-body {
flex-direction: column;
}
.hg-nav, .hg-aside {
flex-basis: auto; /* Auto height when stacked */
}
.hg-nav {
order: -1; /* Move nav above content on mobile */
}
}
Practical Example: Sticky Footer
A sticky footer stays at the bottom of the viewport when content is short, but pushes down naturally when content is tall. This is one of the simplest and most elegant Flexbox patterns.
Example: Sticky Footer
<body class="sticky-footer-layout">
<header>Site Header</header>
<main>Page content that might be short or long...</main>
<footer>Sticky Footer</footer>
</body>
CSS for Sticky Footer
.sticky-footer-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
header {
flex: none; /* Header stays its natural size */
}
main {
flex: 1; /* Main grows to push footer down */
}
footer {
flex: none; /* Footer stays its natural size */
}
The magic is in flex: 1 on the main element. When the content is short, the main area grows to absorb all the extra viewport height, keeping the footer pinned at the bottom. When the content is taller than the viewport, the main area takes its natural height and the footer sits naturally below it.
Practical Example: Media Object
The media object pattern displays an image or icon alongside a block of text. It is ubiquitous in web design -- think of comments, user profiles, notification lists, and social media feeds.
Example: Flexible Media Object
<div class="media-object">
<img class="media-image" src="avatar.jpg" alt="User avatar">
<div class="media-body">
<h3>Username</h3>
<p>This is the comment body text that can be any length and
will naturally wrap within the available space.</p>
</div>
</div>
CSS for Media Object
.media-object {
display: flex;
gap: 16px;
align-items: flex-start;
}
.media-image {
flex: none; /* Image never grows or shrinks */
width: 48px;
height: 48px;
border-radius: 50%;
object-fit: cover;
}
.media-body {
flex: 1; /* Text area takes all remaining space */
min-width: 0; /* Prevent overflow from long words */
}
.media-body h3 {
margin: 0 0 4px;
}
.media-body p {
margin: 0;
color: var(--text-light);
}
Combining Item Properties: Advanced Patterns
Real-world layouts often combine multiple flex item properties to achieve precise control over how elements behave as the container size changes.
Example: Dashboard Panel Sizing
.dashboard-row {
display: flex;
gap: 20px;
}
/* Fixed-width statistics panel */
.stats-panel {
flex: 0 0 300px;
/* Never grows, never shrinks, always 300px */
}
/* Main chart area that fills remaining space */
.chart-panel {
flex: 1 1 0%;
min-width: 0;
/* Grows and shrinks, starts from 0, equal sharing */
}
/* Side info that can shrink but prefers 250px */
.info-panel {
flex: 0 1 250px;
/* Does not grow, can shrink if needed, starts at 250px */
}
Example: Input Group with Button
.input-group {
display: flex;
}
.input-group input {
flex: 1 1 auto;
min-width: 0;
padding: 8px 12px;
border: 1px solid var(--border-light);
border-right: none;
border-radius: 4px 0 0 4px;
}
.input-group button {
flex: none;
padding: 8px 20px;
background: var(--primary);
color: white;
border: 1px solid var(--primary);
border-radius: 0 4px 4px 0;
cursor: pointer;
}
Practice Exercise
Build a card layout with three cards side by side. Each card should use flex: 1 so they share space equally. Inside each card, use a column flex layout with the card footer pushed to the bottom using margin-top: auto. Add a featured card that is twice as wide as the others by using flex: 2. Then add a sidebar on the right with flex: 0 0 250px that never grows or shrinks. Test your layout by resizing the browser window and observe how each item responds. Add min-width: 0 to the cards and place a long URL inside one to verify it truncates properly with text-overflow: ellipsis. Finally, use the order property to visually move the featured card to the first position without changing the HTML source order.