What Is Flexbox and When to Use It
CSS Flexible Box Layout — universally called Flexbox — is a one-dimensional layout system designed to distribute space among items in a container and align them along a single axis. It was introduced to solve the alignment problems that plagued developers for decades: vertical centering, equal-height columns, sticky footers, and space distribution.
Flexbox operates on a main axis and a cross axis. The main axis is the direction your items flow (horizontal by default). The cross axis is perpendicular to it (vertical by default). Every Flexbox property relates to one of these two axes, and once you internalize this mental model, the entire system becomes predictable.
Flexbox vs CSS Grid: When to Use Which
The simplest decision rule: Flexbox is for one-dimensional layouts (a row OR a column), while CSS Grid is for two-dimensional layouts (rows AND columns). In practice, most pages use both. Grid defines the page structure, and Flexbox handles alignment within components. For a detailed comparison, see our CSS Grid vs Flexbox guide.
- Use Flexbox for: navbars, button groups, card content alignment, centering, form input rows, tag lists, breadcrumbs, toolbars
- Use Grid for: page layouts, card grids, dashboards, image galleries, any layout where items must align in both rows and columns
If your layout is a line of things, use Flexbox. If your layout is a grid of things, use CSS Grid. If you are unsure, start with Flexbox — it is simpler and covers the majority of component-level layouts.
The Flex Container: display:flex
Flexbox begins with the container. Apply display: flex to a parent element, and its direct children become flex items. That single property changes the layout model entirely.
.container {
display: flex;
}
By default, this creates a horizontal row of items that stretch to fill the container height. Every child element is now a flex item, regardless of whether it is a div, span, img, or any other element.
flex-direction
The flex-direction property controls which direction the main axis runs. It has four values:
/* Items flow left to right (default) */
.container { flex-direction: row; }
/* Items flow right to left */
.container { flex-direction: row-reverse; }
/* Items flow top to bottom */
.container { flex-direction: column; }
/* Items flow bottom to top */
.container { flex-direction: column-reverse; }
row is the default and the most common. Items line up horizontally. column is used when you want items stacked vertically — think of a sidebar menu, a card's internal structure, or a form's field list. The reverse variants flip the visual order without changing the DOM order, which can be useful for right-to-left interfaces or specific design requirements.
When you change flex-direction to column, the main axis and cross axis swap. This means justify-content now controls vertical alignment and align-items controls horizontal alignment. This catches many beginners off guard.
Main Axis Alignment: justify-content
The justify-content property controls how items are distributed along the main axis. It determines where extra space goes when items do not fill the entire container.
.container {
display: flex;
justify-content: flex-start; /* Items packed to the start (default) */
justify-content: flex-end; /* Items packed to the end */
justify-content: center; /* Items centered */
justify-content: space-between; /* First item at start, last at end, even gaps */
justify-content: space-around; /* Equal space around each item */
justify-content: space-evenly; /* Equal space between and around items */
}
Here is how each value distributes three items in a container. Think of the container as a horizontal bar and the items as boxes inside it:
space-between is ideal for navbars (logo on the left, links on the right). center is the go-to for centering a group of items. space-evenly creates the most visually balanced distribution and is excellent for icon rows or tab bars.
Cross Axis Alignment: align-items
While justify-content handles the main axis, align-items controls how items are positioned along the cross axis. In a row layout, this means vertical alignment.
.container {
display: flex;
align-items: stretch; /* Items stretch to fill container height (default) */
align-items: flex-start; /* Items align to the top */
align-items: center; /* Items vertically centered */
align-items: flex-end; /* Items align to the bottom */
align-items: baseline; /* Items align by their text baseline */
}
The stretch default is why flex items fill the full height of their container — remove it with flex-start if you want items to be their natural height. baseline is particularly useful when items have different font sizes but you want their text to line up.
The classic perfect centering pattern combines both properties:
.centered {
display: flex;
justify-content: center; /* Horizontal center */
align-items: center; /* Vertical center */
min-height: 100vh; /* Full viewport height */
}
This three-line pattern replaces decades of CSS centering hacks. It works for any content: text, images, forms, or entire components.
Wrapping: flex-wrap and align-content
By default, flex items try to fit on a single line, even if it means overflowing the container or shrinking items below their natural size. The flex-wrap property changes this behavior.
.container {
display: flex;
flex-wrap: nowrap; /* All items on one line (default) */
flex-wrap: wrap; /* Items wrap to the next line */
flex-wrap: wrap-reverse; /* Items wrap upward instead of downward */
}
When items wrap, align-content controls how the wrapped lines are distributed within the container. It uses the same values as justify-content but applies to the cross axis:
.container {
display: flex;
flex-wrap: wrap;
align-content: flex-start; /* Lines packed to the top */
align-content: center; /* Lines centered vertically */
align-content: space-between; /* First line at top, last at bottom */
align-content: stretch; /* Lines stretch to fill (default) */
}
align-items positions items within each line. align-content positions the lines themselves within the container. align-content has no effect when there is only one line (when flex-wrap is nowrap or items do not actually wrap).
The Gap Property
The gap property adds spacing between flex items without affecting the outer edges. It replaced margin-based spacing patterns and works in all modern browsers.
.container {
display: flex;
flex-wrap: wrap;
gap: 16px; /* Equal spacing in both directions */
row-gap: 24px; /* Vertical spacing between wrapped rows */
column-gap: 12px; /* Horizontal spacing between items */
gap: 24px 12px; /* Shorthand: row-gap column-gap */
}
Before gap, developers used margin on items and negative margin on the container to avoid outer spacing. The gap property eliminates this hack entirely. It only applies space between items, never on the edges.
Flex Items: flex-grow, flex-shrink, flex-basis
The three flex item properties control how items grow, shrink, and set their initial size. These are the most powerful and most misunderstood parts of Flexbox.
flex-grow
flex-grow determines how much of the remaining space an item takes. The default is 0, meaning items do not grow beyond their content size. Setting it to 1 makes an item absorb all remaining space. If multiple items have flex-grow: 1, they share the remaining space equally.
.sidebar { flex-grow: 0; width: 250px; } /* Fixed width, does not grow */
.main { flex-grow: 1; } /* Takes all remaining space */
.aside { flex-grow: 0; width: 200px; } /* Fixed width, does not grow */
flex-shrink
flex-shrink determines how much an item shrinks when the container is too small. The default is 1, meaning all items shrink equally. Set it to 0 to prevent an item from shrinking below its natural or specified size.
.logo { flex-shrink: 0; } /* Never shrink the logo */
.nav { flex-shrink: 1; } /* Links can shrink if needed */
flex-basis
flex-basis sets the initial size of an item before growing or shrinking occurs. It is similar to width (in row direction) or height (in column direction), but participates in the flex algorithm.
.item { flex-basis: 200px; } /* Start at 200px, then grow/shrink */
.item { flex-basis: 25%; } /* Start at 25% of container */
.item { flex-basis: auto; } /* Use content size (default) */
.item { flex-basis: 0; } /* Ignore content size, distribute all space by grow */
The flex Shorthand
The flex shorthand combines all three properties. It is the recommended way to set flex item sizing:
/* flex: grow shrink basis */
.item { flex: 0 1 auto; } /* Default: don't grow, can shrink, auto basis */
.item { flex: 1; } /* Shorthand for: flex: 1 1 0% — grow equally */
.item { flex: auto; } /* Shorthand for: flex: 1 1 auto — grow from content size */
.item { flex: none; } /* Shorthand for: flex: 0 0 auto — rigid, no flex */
.item { flex: 2; } /* Takes 2x the space of flex: 1 items */
Use flex: 1 to make items share space equally. Use flex: none for fixed-size items (logos, icons, fixed sidebars). Use flex: 2 or higher to give items proportionally more space. These three cover 90% of use cases.
Order and Visual Reordering
The order property lets you change the visual order of flex items without changing the HTML. All items have order: 0 by default. Lower values appear first; higher values appear later.
.container {
display: flex;
}
/* Move sidebar visually before main content on desktop */
.sidebar { order: -1; } /* Appears first */
.main { order: 0; } /* Appears second */
.aside { order: 1; } /* Appears last */
/* On mobile, reset to source order */
@media (max-width: 768px) {
.sidebar { order: 0; }
.main { order: 0; }
.aside { order: 0; }
}
Screen readers and keyboard navigation follow the DOM order, not the visual order. Use the order property sparingly and only for minor visual adjustments. Never use it to restructure content in ways that break reading sequence for assistive technology users.
align-self for Individual Items
While align-items sets the cross-axis alignment for all items, align-self overrides this for a single item. It accepts the same values as align-items.
.container {
display: flex;
align-items: flex-start; /* All items at the top */
}
.special-item {
align-self: flex-end; /* This one at the bottom */
}
.centered-item {
align-self: center; /* This one vertically centered */
}
A common use for align-self is pushing a single item to the opposite end of the cross axis. For example, in a horizontal toolbar, you might want most buttons at the top but a "settings" icon at the bottom. Another frequent pattern is align-self: stretch on a single item in a container where other items do not stretch.
5 Real-World Flexbox Layouts
Layout 1: Navigation Bar
A responsive navbar with logo, links, and action button. The most common Flexbox pattern on the web.
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
height: 64px;
background: #111118;
}
.navbar-logo {
font-weight: 700;
font-size: 1.25rem;
flex-shrink: 0; /* Never shrink the logo */
}
.navbar-links {
display: flex;
gap: 28px;
list-style: none;
}
.navbar-cta {
flex-shrink: 0;
padding: 8px 20px;
background: #6366f1;
border-radius: 8px;
}
Layout 2: Card Grid with Equal Heights
Cards that maintain equal height with content pushed to the bottom. Use Flexbox for the card internals (pair this with CSS Grid or Flexbox wrap for the grid itself). Try building this visually with the Flexbox Playground.
.card-row {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.card {
display: flex;
flex-direction: column;
flex: 1 1 300px; /* Grow, shrink, min 300px */
background: #111118;
border-radius: 12px;
border: 1px solid #1e1e2e;
overflow: hidden;
}
.card-body {
flex: 1; /* Takes remaining space */
padding: 20px;
}
.card-footer {
padding: 16px 20px;
border-top: 1px solid #1e1e2e;
margin-top: auto; /* Pushed to bottom */
}
Layout 3: Holy Grail Layout
Header, footer, main content, and two sidebars — implemented entirely with Flexbox.
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-body {
display: flex;
flex: 1;
}
.sidebar-left { flex: 0 0 220px; }
.main-content { flex: 1; padding: 24px; }
.sidebar-right { flex: 0 0 200px; }
@media (max-width: 768px) {
.page-body { flex-direction: column; }
.sidebar-left,
.sidebar-right { flex: none; }
}
Layout 4: Sticky Footer
A footer that stays at the bottom of the viewport even when content is short, without using position: fixed.
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-header { /* Natural height */ }
.page-content {
flex: 1; /* Absorbs all remaining space */
}
.page-footer { /* Natural height, always at bottom */ }
This is one of the simplest and most effective Flexbox patterns. The flex: 1 on the content area makes it expand to fill all available space, pushing the footer to the bottom regardless of how little content exists.
Layout 5: Perfect Centering
Center any element both horizontally and vertically.
/* Center within the viewport */
.hero {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
}
/* Center within a specific container */
.modal-overlay {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.6);
}
.modal {
max-width: 500px;
width: 90%;
background: #111118;
border-radius: 16px;
padding: 32px;
}
Want to test how these layouts respond at different viewport sizes? Use the Responsive Design Tester to preview your Flexbox layouts on every screen size without leaving your browser.
Build Flexbox Layouts Visually
Experiment with every Flexbox property in real time. Change values, see results instantly, and copy production-ready CSS.
Flexbox Playground CSS Grid GeneratorCommon Flexbox Gotchas and Fixes
Gotcha 1: Items Overflow Instead of Wrapping
Flex items default to flex-wrap: nowrap, which means they will shrink or overflow rather than move to the next line. Add flex-wrap: wrap to the container.
/* Problem: items overflow on small screens */
.tags { display: flex; gap: 8px; }
/* Fix: allow wrapping */
.tags { display: flex; flex-wrap: wrap; gap: 8px; }
Gotcha 2: Image Distortion
Images inside flex items can stretch because align-items: stretch is the default. Fix it by setting the image or its container to align-self: flex-start or using object-fit.
/* Problem: image stretches vertically */
.card { display: flex; gap: 16px; }
.card img { width: 100px; }
/* Fix: prevent stretching */
.card img { width: 100px; align-self: flex-start; }
/* Or use object-fit */
.card img { width: 100px; height: 100px; object-fit: cover; }
Gotcha 3: Text Overflow in Flex Items
Long text in a flex item can push sibling items off-screen because flex items have min-width: auto by default. Fix it with min-width: 0 or overflow: hidden.
/* Problem: long filename pushes button off screen */
.file-row { display: flex; gap: 12px; align-items: center; }
.file-name { /* overflows */ }
/* Fix */
.file-name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
Gotcha 4: Last Row Stretching with flex-wrap
When using flex-wrap: wrap with flex-grow, items on the last row stretch to fill the entire width. If you have three columns and the last row has two items, each takes 50% instead of 33%.
/* Problem: last row items are too wide */
.grid { display: flex; flex-wrap: wrap; gap: 16px; }
.grid-item { flex: 1 1 300px; }
/* Fix option 1: use max-width */
.grid-item { flex: 1 1 300px; max-width: calc(33.333% - 11px); }
/* Fix option 2: use CSS Grid instead (recommended) */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
}
This last-row problem is the main reason developers reach for CSS Grid for card grids. Grid maintains equal column widths on every row automatically.
Gotcha 5: Margin Collapse Does Not Happen in Flexbox
Unlike block layout, margins in Flexbox never collapse. If you have margin-bottom: 20px on one item and margin-top: 20px on the next, you get 40px of space, not 20px. This is expected behavior, but it surprises developers who are used to margin collapsing in normal flow. Use gap instead of margins for spacing between flex items.
Tools for Experimenting with Flexbox
The fastest way to learn Flexbox is to experiment with it visually. Change a property, see the result immediately. Here are free tools that make this possible:
Frequently Asked Questions
Flexbox is a one-dimensional layout system that arranges items along a single axis (row or column). CSS Grid is a two-dimensional layout system that controls both rows and columns simultaneously. Use Flexbox for component-level alignment like navbars, button groups, and card content. Use Grid for page-level structure like dashboards, card grids, and multi-column layouts. Most modern websites use both together.
justify-content controls alignment along the main axis (the direction items flow). align-items controls alignment along the cross axis (perpendicular to the main axis). In a default row direction, justify-content is horizontal and align-items is vertical. In column direction, they swap: justify-content becomes vertical and align-items becomes horizontal.
flex: 1 is shorthand for flex-grow: 1, flex-shrink: 1, flex-basis: 0%. It tells the item to grow and fill all available space in the flex container. If multiple items have flex: 1, they share the available space equally. If one item has flex: 2 and another has flex: 1, the first item takes twice as much space as the second.
Apply display: flex, justify-content: center, and align-items: center to the parent container. If you want to center within the full viewport, also add min-height: 100vh. This three-property pattern is the most reliable way to center any element in CSS and works in all modern browsers.
Yes. The gap property works with Flexbox in all modern browsers since 2021. You can use gap for equal spacing, row-gap for vertical spacing only, and column-gap for horizontal spacing only. The gap property is preferred over margin-based spacing because it only applies between items, not on the outer edges, and it works correctly with flex-wrap.