CSS Flexbox
Introduction
Flexbox (Flexible Box Layout) is a CSS layout system designed to make it easy to arrange elements in rows or columns. Before Flexbox, creating layouts required using floats, positioning tricks, and complex CSS hacks. Flexbox solves common layout problems elegantly.
What Problems Does Flexbox Solve?
- Vertical centering - Centering an element vertically used to be surprisingly difficult
- Equal height columns - Making sibling elements the same height regardless of content
- Flexible spacing - Distributing space evenly between items
- Responsive layouts - Elements that adapt to available space without media queries
The Flex Model
Flexbox works with two types of elements:
Flex Container
The parent element with display: flex applied. It controls how its children are laid out.
Flex Items
The direct children of a flex container. These are the elements being arranged.
<div class="container">
<!-- Flex Container -->
<div class="item">1</div>
<!-- Flex Item -->
<div class="item">2</div>
<!-- Flex Item -->
<div class="item">3</div>
<!-- Flex Item -->
</div>.container {
display: flex; /* This makes the div a flex container */
}Understanding Axes
Flexbox operates along two axes. This is the most important concept to understand.
Main Axis
The primary axis along which flex items are placed. By default, this runs horizontally (left to right).
Cross Axis
The axis perpendicular to the main axis. By default, this runs vertically (top to bottom).
Default axes (flex-direction: row):
Main Axis →
┌─────────────────────────┐
│ ┌───┐ ┌───┐ ┌───┐ │ ↓
│ │ 1 │ │ 2 │ │ 3 │ │ Cross
│ └───┘ └───┘ └───┘ │ Axis
└─────────────────────────┘Memory Trick: “Justify works on the Main axis (both have letters that go below the baseline: j, y, g). Align works on the Cross axis.”
Or simply: Justify = horizontal (like text justification), Align = vertical
Flex Container Properties
These properties are applied to the parent (flex container).
display: flex
Creates a flex container and enables flexbox layout.
.container {
display: flex;
}flex-direction
Sets the direction of the main axis.
| Value | Description |
|---|---|
row | Left to right (default) |
row-reverse | Right to left |
column | Top to bottom |
column-reverse | Bottom to top |
.container {
display: flex;
flex-direction: column; /* Items stack vertically */
}flex-direction: row flex-direction: column
┌──────────────────┐ ┌──────────────────┐
│ ┌──┐ ┌──┐ ┌──┐ │ │ ┌──────────────┐ │
│ │1 │ │2 │ │3 │ │ │ │ 1 │ │
│ └──┘ └──┘ └──┘ │ │ └──────────────┘ │
└──────────────────┘ │ ┌──────────────┐ │
│ │ 2 │ │
│ └──────────────┘ │
│ ┌──────────────┐ │
│ │ 3 │ │
│ └──────────────┘ │
└──────────────────┘justify-content
Controls how items are distributed along the main axis.
| Value | Description |
|---|---|
flex-start | Items packed at the start (default) |
flex-end | Items packed at the end |
center | Items centered |
space-between | Equal space between items, no space at edges |
space-around | Equal space around each item |
space-evenly | Truly equal space everywhere |
.container {
display: flex;
justify-content: space-between;
}justify-content: flex-start justify-content: center
┌──────────────────────┐ ┌──────────────────────┐
│┌──┐┌──┐┌──┐ │ │ ┌──┐┌──┐┌──┐ │
│└──┘└──┘└──┘ │ │ └──┘└──┘└──┘ │
└──────────────────────┘ └──────────────────────┘
justify-content: space-between justify-content: space-evenly
┌──────────────────────┐ ┌──────────────────────┐
│┌──┐ ┌──┐ ┌──┐│ │ ┌──┐ ┌──┐ ┌──┐ │
│└──┘ └──┘ └──┘│ │ └──┘ └──┘ └──┘ │
└──────────────────────┘ └──────────────────────┘align-items
Controls how items are aligned along the cross axis.
| Value | Description |
|---|---|
stretch | Items stretch to fill container (default) |
flex-start | Items aligned to the start of cross axis |
flex-end | Items aligned to the end of cross axis |
center | Items centered on cross axis |
baseline | Items aligned by their text baseline |
.container {
display: flex;
align-items: center; /* Vertically centers items */
}align-items: flex-start align-items: center
┌──────────────────────┐ ┌──────────────────────┐
│┌──┐ ┌────┐ ┌──┐ │ │ │
│└──┘ │ │ └──┘ │ │┌──┐ ┌────┐ ┌──┐ │
│ │ │ │ │└──┘ │ │ └──┘ │
│ └────┘ │ │ └────┘ │
└──────────────────────┘ └──────────────────────┘flex-wrap
Controls whether items wrap to new lines when they don’t fit.
| Value | Description |
|---|---|
nowrap | All items stay on one line (default) |
wrap | Items wrap to new lines |
wrap-reverse | Items wrap in reverse order |
.container {
display: flex;
flex-wrap: wrap; /* Items wrap when container is too narrow */
}gap
Sets spacing between flex items. This is the recommended way to add space between items (better than using margins).
.container {
display: flex;
gap: 20px; /* Same gap in both directions */
/* Or specify separately: */
row-gap: 10px; /* Vertical gap */
column-gap: 20px; /* Horizontal gap */
}Why use gap instead of margins?
- Gap only creates space between items, not around them
- Cleaner code - no need for
:first-childor:last-childexceptions - Works consistently in both directions
Flex Item Properties
These properties are applied to the children (flex items).
flex-grow
Determines how much an item should grow relative to other items when there’s extra space.
.item {
flex-grow: 1; /* Item will grow to fill available space */
}All items flex-grow: 0 (default) All items flex-grow: 1
┌────────────────────────────┐ ┌────────────────────────────┐
│┌──┐ ┌──┐ ┌──┐ │ │┌────────┐┌────────┐┌──────┐│
│└──┘ └──┘ └──┘ │ │└────────┘└────────┘└──────┘│
└────────────────────────────┘ └────────────────────────────┘
Item 2 has flex-grow: 2, others have flex-grow: 1
┌────────────────────────────┐
│┌─────┐┌──────────┐┌──────┐│
│└─────┘└──────────┘└──────┘│
└────────────────────────────┘
(1) (2x) (1)flex-shrink
Determines how much an item should shrink relative to other items when there isn’t enough space.
.item {
flex-shrink: 0; /* Item will not shrink */
}- Default value is
1(items shrink equally) - Set to
0to prevent an item from shrinking
flex-basis
Sets the initial size of an item before growing or shrinking.
.item {
flex-basis: 200px; /* Start at 200px, then grow/shrink */
}- Similar to
widthbut specific to flexbox - Use
autoto use the item’s content size
The flex Shorthand
Combines flex-grow, flex-shrink, and flex-basis into one property.
.item {
flex: 1; /* flex-grow: 1, flex-shrink: 1, flex-basis: 0% */
flex: 0 0 200px; /* Don't grow, don't shrink, start at 200px */
flex: 1 0 auto; /* Grow, don't shrink, use content size */
}Common values:
flex: 1- Item grows to fill space, commonly usedflex: 0 0 auto- Item stays at its content sizeflex: 0 0 200px- Item stays fixed at 200px
order
Changes the visual order of items without changing the HTML.
.item-3 {
order: -1; /* Moves this item to the beginning */
}- Default is
0 - Lower numbers appear first
- Useful for responsive layouts
align-self
Overrides the container’s align-items for a specific item.
.special-item {
align-self: flex-end; /* This item aligns to the bottom */
}Common Patterns
Centering an Element (Horizontally and Vertically)
The classic problem that Flexbox makes trivial:
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* Full viewport height */
}Navigation Bar
<nav class="navbar">
<div class="logo">Logo</div>
<ul class="nav-links">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>.navbar {
display: flex;
justify-content: space-between; /* Logo on left, links on right */
align-items: center;
padding: 1rem 2rem;
}
.nav-links {
display: flex;
gap: 2rem;
list-style: none;
}Card Row with Equal Heights
.card-container {
display: flex;
gap: 20px;
}
.card {
flex: 1; /* Cards grow equally */
display: flex;
flex-direction: column;
}
.card-content {
flex: 1; /* Content area grows to fill card */
}Sticky Footer Layout
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1; /* Main content grows to push footer down */
}
footer {
/* Footer stays at bottom */
}Troubleshooting & Common Mistakes
Items not centering?
- Check that the container has a defined height
- Make sure you’re using both
justify-contentandalign-items
Items overflowing the container?
- Add
flex-wrap: wrapto allow wrapping - Or set
flex-shrink: 1on items to let them shrink
Confusing justify-content with align-items?
- justify-content = main axis (horizontal by default)
- align-items = cross axis (vertical by default)
- Remember:
flex-directionchanges which axis is which!
Gap not working?
- Make sure the container has
display: flex - Check browser support (gap in Flexbox is widely supported in modern browsers)
Item not respecting width?
- Flex items can shrink by default
- Use
flex-shrink: 0to prevent shrinking - Or use
flex: 0 0 [width]as a shorthand
Key Takeaways
- Flexbox is one-dimensional - it handles either rows OR columns (use Grid for two-dimensional layouts)
- The main axis is determined by
flex-direction justify-content= main axis,align-items= cross axis- Use gap instead of margins for spacing between items
- The
flexshorthand (flex: 1) is commonly used for items that should grow - Flexbox is ideal for component-level layouts (navbars, cards, form elements)
Additional Resources
Official Documentation
Interactive Learning
Visual References
Tools
- Use your browser’s DevTools (F12) - the Flexbox inspector helps visualize the layout