Everything real developers know — clear definitions, live demos, and practical examples. No fluff.
Before these two existed, developers used floats, tables, and inline-block hacks just to center a div. It was painful. Then CSS gave us two dedicated layout tools:
Simple rule: Use Flexbox for 1D layouts (a row of buttons, a nav, a card's inner content). Use Grid for 2D layouts (whole page structure, image galleries, dashboards).
Flexbox works by designating one element as a flex container. Its direct children automatically become flex items and are laid out according to flexbox rules.
.container { display: flex; /* That's it. Now children are flex items. */ }
Flexbox has two axes. Every alignment property targets one of them. This is the most important concept to understand.
justify-content controls the main axis. align-items controls the cross axis. Remember this and flex makes sense.
These go on the parent (the element with display: flex).
Sets which direction the main axis runs.
| Value | Effect | Description |
|---|---|---|
| row | → | Default. Items go left to right. |
| row-reverse | ← | Items go right to left. |
| column | ↓ | Items stack top to bottom. |
| column-reverse | ↑ | Items stack bottom to top. |
.container { display: flex; flex-direction: column; /* stack vertically */ }
Distributes items along the main axis (horizontal by default).
| Value | Behavior | Use case |
|---|---|---|
| flex-start | Pack to start | Default behavior |
| flex-end | Pack to end | Right-align buttons |
| center | Center all items | Centered nav |
| space-between | First→start, Last→end, equal space between | Nav with logo + links |
| space-around | Equal space around each item | Even distribution |
| space-evenly | Perfectly equal space everywhere | Tab bars |
Controls how items are placed along the cross axis (vertical by default).
| Value | Behavior |
|---|---|
| stretch | Default. Items stretch to fill the container height. |
| flex-start | Align to the top (cross start). |
| flex-end | Align to the bottom (cross end). |
| center | Vertically center items. The most useful one. |
| baseline | Align text baselines across items. |
Perfect centering trick: display: flex; justify-content: center; align-items: center; — centers anything both horizontally and vertically. No more margin: auto hacks.
By default, flex items try to fit on one line. flex-wrap: wrap lets them break to the next line when they run out of space.
.container { display: flex; flex-wrap: wrap; /* wrap to next line */ flex-wrap: nowrap; /* (default) force one line */ flex-wrap: wrap-reverse; /* wrap upward */ }
Adds space between flex items. Much cleaner than using margins.
.container { display: flex; gap: 16px; /* same gap in all directions */ gap: 16px 8px; /* row-gap column-gap */ row-gap: 16px; /* only between rows */ column-gap: 8px; /* only between columns */ }
When items wrap to multiple lines, align-content controls how those lines are distributed vertically. Same values as justify-content.
align-content vs align-items: align-items aligns items within a single row. align-content aligns the whole group of rows. It only works when flex-wrap: wrap is set.
These go on the children (the flex items themselves).
Tells an item how much of the remaining space to claim. Default is 0 (don't grow).
.sidebar { flex-grow: 1; } /* claims 1 share */ .main { flex-grow: 3; } /* claims 3 shares (3x bigger) */
Controls how much an item shrinks when there's not enough space. Default is 1 (shrink proportionally). Set to 0 to prevent shrinking.
.logo { flex-shrink: 0; /* Never squish the logo */ }
Sets the initial size of the item before any growing or shrinking happens. Think of it as the "starting width" (or height in column mode).
.item { flex-basis: 200px; /* start at 200px, then grow/shrink */ flex-basis: auto; /* (default) use the item's natural size */ flex-basis: 0; /* start from 0, distribute all space via flex-grow */ }
In real code, you'll almost always use the flex shorthand instead of the three individual properties.
.item { flex: 1; /* flex: 1 1 0% — most common, equal columns */ flex: auto; /* flex: 1 1 auto */ flex: none; /* flex: 0 0 auto — rigid, won't grow or shrink */ flex: 2 1 100px; /* grow:2, shrink:1, start at 100px */ }
Overrides align-items for a single item. Let one item do something different from the rest.
.container { align-items: center; } .special { align-self: flex-end; /* only this item goes to the bottom */ }
Changes the visual order of flex items without changing the HTML. Default is 0 for all items.
.first-visually { order: -1; } /* appears first */ .last-visually { order: 99; } /* appears last */
CSS Grid divides a container into a defined table of rows and columns. You then assign items to specific cells. It's purpose-built for 2D layouts.
.container { display: grid; grid-template-columns: 200px 1fr 1fr; /* 3 columns */ grid-template-rows: auto 1fr 60px; /* 3 rows */ }
The fr unit means "fraction of available space". It's the most important Grid unit. It's like flex-grow but for grid tracks.
/* 3 equal columns */ grid-template-columns: 1fr 1fr 1fr; /* Sidebar + big content + small aside */ grid-template-columns: 1fr 3fr 1fr; /* Fixed sidebar + flexible content */ grid-template-columns: 250px 1fr;
When you define a grid, CSS automatically numbers the lines between columns and rows. These numbers let you place items precisely.
Define your grid's structure. These are the most fundamental Grid properties.
.container { grid-template-columns: 100px 200px 100px; /* fixed sizes */ grid-template-columns: 1fr 2fr 1fr; /* proportional */ grid-template-columns: repeat(4, 1fr); /* 4 equal columns */ grid-template-columns: repeat(3, minmax(100px, 1fr)); grid-template-rows: 80px 1fr 60px; /* header + main + footer heights */ }
Shorthand to avoid repeating yourself. Real developers use this constantly.
/* Instead of this: */ grid-template-columns: 1fr 1fr 1fr 1fr 1fr; /* Write this: */ grid-template-columns: repeat(5, 1fr); /* Auto-fill as many as fit: */ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
repeat(auto-fill, minmax(200px, 1fr)) is one of the most powerful CSS lines you can write — it creates a fully responsive card grid with zero media queries.
Same as Flexbox — adds space between grid cells.
.container { gap: 20px; /* same row and column gap */ gap: 20px 10px; /* row-gap: 20px, column-gap: 10px */ }
This is the superpower of Grid. You draw your layout visually with names. It makes complex layouts obvious to read and maintain.
.container { display: grid; grid-template-columns: 200px 1fr; grid-template-rows: 60px 1fr 50px; grid-template-areas: "header header" /* header spans both columns */ "sidebar main" "footer footer"; /* footer spans both columns */ } /* Assign items to named areas */ .header { grid-area: header; } .sidebar { grid-area: sidebar; } .main { grid-area: main; } .footer { grid-area: footer; }
Control how items are aligned inside their grid cells.
| Property | Direction | Values |
|---|---|---|
| justify-items | Horizontal (inline) | start, end, center, stretch |
| align-items | Vertical (block) | start, end, center, stretch |
| place-items | Both at once | align-items / justify-items |
.container { place-items: center; /* center both axes */ place-items: center start; /* center vertically, start horizontally */ }
When the grid is smaller than its container, these distribute the tracks themselves inside the container (same concept as Flexbox).
These go on the children to control exactly where they sit in the grid.
Tell an item which column/row lines to start and end at. This lets items span multiple cells.
.hero-image { grid-column: 1 / 3; /* from line 1 to line 3 (spans 2 columns) */ grid-row: 1 / 2; /* from line 1 to line 2 (1 row) */ } /* Span keyword is cleaner: */ .wide-item { grid-column: span 2; /* span 2 columns, wherever it lands */ grid-row: span 3; /* span 3 rows */ } /* -1 means the last line: */ .full-width { grid-column: 1 / -1; /* span the ENTIRE width */ }
The shorthand combining all four line properties, or a reference to a named template area.
/* As named area reference: */ .header { grid-area: header; } /* As line shorthand: row-start / col-start / row-end / col-end */ .item { grid-area: 1 / 1 / 3 / 3; }
Override alignment for a single item inside its cell.
.centered-item { justify-self: center; /* center horizontally in its cell */ align-self: end; /* stick to bottom of its cell */ place-self: center; /* both at once — center in cell */ }
nav { display: flex; justify-content: space-between; align-items: center; padding: 0 2rem; height: 64px; } nav ul { display: flex; gap: 2rem; list-style: none; }
.card-row { display: flex; gap: 1.5rem; flex-wrap: wrap; } .card { flex: 1 1 280px; /* grow, shrink, min 280px */ display: flex; flex-direction: column; } .card .btn { margin-top: auto; /* push button to bottom of card */ }
body { display: grid; min-height: 100vh; grid-template-columns: 250px 1fr; grid-template-rows: 64px 1fr 60px; grid-template-areas: "header header" "sidebar main" "footer footer"; } header { grid-area: header; } aside { grid-area: sidebar; } main { grid-area: main; } footer { grid-area: footer; }
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; } /* That's literally it. */
/* Method 1 — Flexbox */ .center-flex { display: flex; justify-content: center; align-items: center; } /* Method 2 — Grid (even shorter) */ .center-grid { display: grid; place-items: center; }
| Situation | Use Flexbox | Use Grid |
|---|---|---|
| Dimensions | One direction (row OR column) | Both directions (rows AND columns) |
| Content vs Layout | Content-driven (items decide their own size) | Layout-driven (you define the structure) |
| Use case | Navbars, button groups, card content, forms | Page layouts, dashboards, galleries, magazine grids |
| Complexity | Simpler, fewer properties to remember | More powerful, better for complex 2D layouts |
| Overlap? | Items never overlap (they push each other) | Items CAN overlap using the same cell |
Real dev mental model: Grid for the big picture (page skeleton), Flexbox for the detail work inside each section. They complement each other — use both in the same page, often nested.