When to Use Grid vs. Flexbox
Flexbox and Grid are both CSS layout tools, but each has different strengths. Flexbox excels at one-dimensional (horizontal or vertical) layouts, while Grid excels at two-dimensional (horizontal + vertical) layouts.
Using a bookshelf analogy, Flexbox is like arranging books side by side on a single shelf, while Grid is like designing an entire grid-style storage unit.
| Criteria | Flexbox | Grid |
|---|---|---|
| Dimension | 1D (row or column) | 2D (row + column) |
| Best for | Navigation, card rows, alignment | Page layouts, dashboards |
| Item sizing | Content-based | Track-based |
| Alignment | Single axis | Both axes |
Flexbox Core Patterns
Basic Layout
/* Navigation bar — logo left, menu right */
.navbar {
display: flex;
justify-content: space-between; /* Push to opposite ends */
align-items: center; /* Vertically center */
padding: 1rem 2rem;
gap: 1rem; /* Spacing between items */
}
.nav-menu {
display: flex;
gap: 1.5rem; /* Spacing between menu items */
list-style: none;
}
/* Card row — equal distribution + wrapping */
.card-row {
display: flex;
flex-wrap: wrap; /* Wrap when space is insufficient */
gap: 1rem;
}
.card {
flex: 1 1 300px; /* Min 300px, remaining space distributed equally */
/* flex-grow: 1 → fills remaining space */
/* flex-shrink: 1 → shrinks when space is tight */
/* flex-basis: 300px → base width */
}
Common Alignment Patterns
/* Perfect centering (the cleanest approach) */
.center-everything {
display: flex;
justify-content: center; /* Horizontal center */
align-items: center; /* Vertical center */
min-height: 100vh;
}
/* Sticky footer at the bottom */
.page-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-content {
flex: 1; /* Takes all remaining space → pushes footer down */
}
.page-footer {
/* flex: 0 maintains natural height */
}
/* Right-align only the last item */
.toolbar {
display: flex;
gap: 0.5rem;
}
.toolbar .spacer {
margin-left: auto; /* Push with auto margin */
}
CSS Grid Core Patterns
Page Layout
/* Classic sidebar + main content layout */
.page-grid {
display: grid;
grid-template-columns: 250px 1fr; /* Sidebar 250px, rest for main */
grid-template-rows: auto 1fr auto; /* Header, content, footer */
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
gap: 1rem;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
/* Responsive — hide sidebar on mobile */
@media (max-width: 768px) {
.page-grid {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"footer";
}
.sidebar { display: none; }
}
Auto-Responsive Card Grid
/* auto-fill + minmax — responsive without media queries */
.auto-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
padding: 1rem;
}
/* auto-fill vs auto-fit difference */
/* auto-fill: empty tracks still take up space (maintains alignment) */
/* auto-fit: removes empty tracks (items fill remaining space) */
.auto-grid-fit {
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
/* When there are few items → items stretch to fill */
}
Dashboard Layout
/* Dashboard with widgets of varying sizes */
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 200px; /* Each row height 200px */
gap: 1rem;
}
/* Size specifications per widget */
.widget-wide {
grid-column: span 2; /* 2 columns wide */
}
.widget-tall {
grid-row: span 2; /* 2 rows tall */
}
.widget-large {
grid-column: span 2;
grid-row: span 2; /* 2 columns x 2 rows */
}
/* Responsive dashboard */
@media (max-width: 1024px) {
.dashboard {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 640px) {
.dashboard {
grid-template-columns: 1fr;
}
.widget-wide,
.widget-tall,
.widget-large {
grid-column: span 1;
grid-row: span 1;
}
}
Container Query: Component-Level Responsiveness
Traditional media queries are based on the viewport (browser window), but Container Queries apply styles based on the parent container. The same card component can automatically switch from vertical layout in a sidebar to horizontal layout in the main area.
/* 1. Declare container */
.card-container {
container-type: inline-size; /* Enable container query based on width */
container-name: card; /* Optional name assignment */
}
/* 2. Default card style (narrow container) */
.card {
display: flex;
flex-direction: column; /* Default: vertical layout */
border-radius: 12px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.card-image {
aspect-ratio: 16 / 9;
object-fit: cover;
width: 100%;
}
.card-body {
padding: 1rem;
}
/* 3. Container query — switch to horizontal layout when container is 500px or wider */
@container card (min-width: 500px) {
.card {
flex-direction: row; /* Switch to horizontal layout */
}
.card-image {
width: 200px;
aspect-ratio: 1; /* Change to square */
}
}
/* 4. Show additional info in wider containers */
@container card (min-width: 700px) {
.card-meta {
display: flex; /* Show meta information */
gap: 0.5rem;
}
.card-description {
-webkit-line-clamp: 3; /* Show up to 3 lines */
}
}
Subgrid: Inheriting Parent Grid Lines
Subgrid allows child elements to inherit the parent Grid’s track lines, ensuring alignment consistency even in nested grids.
/* Parent grid */
.product-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
/* Card aligns internal elements (image, title, price) across cards */
.product-card {
display: grid;
grid-template-rows: subgrid; /* Inherit parent's row tracks */
grid-row: span 3; /* Occupy 3 rows */
gap: 0.5rem;
border: 1px solid #e5e7eb;
border-radius: 8px;
overflow: hidden;
}
/* Result: image height, title height, and price height align across all cards */
.product-image { /* First row */ }
.product-title { /* Second row — aligned with other cards */ }
.product-price { /* Third row — aligned with other cards */ }
Layout Selection Guide
| Scenario | Recommended Approach |
|---|---|
| Arrange items in a single row | Flexbox |
| Place items in an even grid | Grid + auto-fill |
| Full page structure (header, sidebar, main) | Grid + grid-template-areas |
| Vertical centering | Flexbox align-items: center |
| Responsive card layout | Grid + minmax() |
| Component-level responsiveness | Container Query |
| Consistent alignment in nested grids | Subgrid |
Practical Tips
- Mix Grid and Flexbox: Use Grid for the overall page layout and Flexbox for component-level arrangements. This is the natural combination.
- Try
auto-fill + minmaxfirst: You can create responsive layouts without any media queries. - Make components independent with Container Query: When components respond to their parent’s size instead of the viewport, they work well no matter where you place them.
- Use the
gapproperty generously: Usingmarginfor spacing requires special handling for first/last items, butgaponly applies between items. - Visualize layouts with
grid-template-areas: Expressing layouts like ASCII art greatly improves code readability. - Use DevTools Grid/Flexbox inspectors: Both Chrome and Firefox let you visually inspect Grid lines and Flexbox structures.