Layout (Flexbox and Grid)
The conventional contemporary CSS layout uses Flexbox (one-dimensional layout — rows or columns) and CSS Grid (two-dimensional layout — rows and columns simultaneously). Both replace the older mechanisms (floats, tables for layout, inline-block hacks) with substantial declarative layout. Flexbox is the conventional choice for one-dimensional alignment — navigation bars, button groups, card rows. Grid is the conventional choice for two-dimensional layout — page-level structure, dashboards, complex card grids. The combination — Flexbox for one-axis alignment, Grid for two-axis layout, the substantial alignment properties (justify-content, align-items, place-items), the responsive integration via media and container queries — is the substance of CSS’s modern layout surface.
Flexbox basics
Make an element a flex container via display: flex:
.container {
display: flex;
}
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
The principal axes:
- Main axis — direction of
flex-direction(defaultrow). - Cross axis — perpendicular.
.container {
flex-direction: row; /* default: left-to-right */
flex-direction: column; /* top-to-bottom */
flex-direction: row-reverse; /* right-to-left */
flex-direction: column-reverse; /* bottom-to-top */
}
Flex alignment
.container {
display: flex;
/* Main axis: */
justify-content: flex-start; /* default; pack at start */
justify-content: flex-end;
justify-content: center;
justify-content: space-between; /* spread; first/last at edges */
justify-content: space-around; /* equal space around each */
justify-content: space-evenly; /* equal space everywhere */
/* Cross axis (single line): */
align-items: stretch; /* default; fill cross axis */
align-items: flex-start;
align-items: flex-end;
align-items: center;
align-items: baseline; /* align text baselines */
/* Cross axis (multi-line): */
align-content: flex-start; /* applies when wrapping */
align-content: space-between;
align-content: center;
}
For individual item override:
.item {
align-self: center; /* override container's align-items */
}
Flex item sizing
.item {
flex: 1; /* shorthand: 1 1 0 */
flex: 0 0 auto; /* default */
flex: 1 1 200px; /* grow shrink basis */
/* Or individually: */
flex-grow: 1; /* admit growing */
flex-shrink: 1; /* admit shrinking */
flex-basis: 200px; /* preferred size */
}
The principal patterns:
flex: 1— share remaining space equally.flex: 0 0 auto— fixed size based on content (default).flex: 0 0 200px— fixed 200px width.flex: 1 1 200px— preferred 200px, grow/shrink as needed.
.sidebar { flex: 0 0 200px; } /* fixed width */
.main { flex: 1; } /* fill remaining */
Flex wrap
.container {
display: flex;
flex-wrap: nowrap; /* default; single line */
flex-wrap: wrap; /* multiple lines */
flex-wrap: wrap-reverse;
}
.container {
flex-flow: row wrap; /* shorthand for direction + wrap */
}
For gaps:
.container {
display: flex;
gap: 1rem; /* gap between items */
row-gap: 1rem; /* between rows */
column-gap: 0.5rem; /* between columns */
}
Flexbox common patterns
Centred element
.center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
Navigation bar
.nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
.nav__brand { font-weight: bold; }
.nav__links {
display: flex;
gap: 1rem;
list-style: none;
}
Card row
.card-row {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.card {
flex: 1 1 250px; /* min 250px, grow */
background: white;
padding: 1rem;
border-radius: 0.5rem;
}
Sidebar layout
.layout {
display: flex;
min-height: 100vh;
}
.sidebar {
flex: 0 0 250px;
background: lightgray;
}
.main {
flex: 1;
padding: 2rem;
}
Equal-height columns
.columns {
display: flex;
align-items: stretch; /* default; admits equal heights */
}
.column {
flex: 1;
background: white;
padding: 1rem;
}
Push to right
.toolbar {
display: flex;
align-items: center;
}
.toolbar__spacer {
margin-left: auto; /* push subsequent items right */
}
<div class="toolbar">
<button>A</button>
<button>B</button>
<span class="toolbar__spacer"></span>
<button>C</button> <!-- right-aligned -->
</div>
CSS Grid basics
Make an element a grid container via display: grid:
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* three equal columns */
gap: 1rem;
}
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
Grid template
.container {
display: grid;
/* Columns: */
grid-template-columns: 200px 1fr 200px; /* fixed-flex-fixed */
grid-template-columns: repeat(3, 1fr); /* three equal */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* responsive */
grid-template-columns: 200px auto 1fr;
grid-template-columns: 25% 25% 25% 25%;
/* Rows: */
grid-template-rows: auto 1fr auto; /* header, content, footer */
grid-template-rows: repeat(3, 100px);
/* Gaps: */
gap: 1rem;
column-gap: 0.5rem;
row-gap: 1rem;
}
The fr unit admits fractional size — divides remaining space proportionally.
The repeat(auto-fit, minmax(200px, 1fr)) admits responsive grid — fills as many columns as fit, each at least 200px:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
Grid items
.item {
/* By line numbers: */
grid-column: 1 / 3; /* span columns 1 to 3 */
grid-column: 1 / span 2; /* start at 1, span 2 */
grid-column-start: 1;
grid-column-end: 3;
grid-row: 2 / 4;
grid-row: span 2;
/* Shorthand: */
grid-area: 1 / 2 / 3 / 4; /* row-start / col-start / row-end / col-end */
}
Named grid areas
.container {
display: grid;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
grid-template-columns: 200px 1fr 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
The mechanism admits substantial visual layout in CSS — the template strings look like the layout.
Grid alignment
.container {
display: grid;
/* Items within their cells: */
justify-items: stretch; /* horizontal, default */
align-items: stretch; /* vertical, default */
place-items: center; /* shorthand */
/* The grid within the container: */
justify-content: start; /* horizontal */
align-content: start; /* vertical */
place-content: center; /* shorthand */
}
.item {
justify-self: end; /* per-item horizontal */
align-self: center; /* per-item vertical */
place-self: center end; /* shorthand: align-self justify-self */
}
Implicit grid
When items overflow the explicit grid:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* Implicit row sizes: */
grid-auto-rows: minmax(100px, auto);
/* Direction of auto-placement: */
grid-auto-flow: row; /* default */
grid-auto-flow: column;
grid-auto-flow: dense; /* fill gaps */
}
Grid common patterns
Holy Grail layout
.layout {
display: grid;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
Responsive card grid
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
The auto-fit admits as many columns as fit; each card is min 250px, growing equally.
auto-fill vs auto-fit
.with-auto-fill {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* Empty tracks remain at minmax min when fewer items */
}
.with-auto-fit {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
/* Empty tracks collapse; remaining items grow */
}
The conventional contemporary choice is auto-fit — admits substantial filling of available space.
Form layout
.form {
display: grid;
grid-template-columns: max-content 1fr;
gap: 1rem;
align-items: center;
}
label { justify-self: end; }
Image gallery with varying spans
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 200px;
gap: 0.5rem;
}
.featured {
grid-column: span 2;
grid-row: span 2;
}
Subgrid (modern)
.parent {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
}
.child {
grid-column: 1 / -1; /* full width */
display: grid;
grid-template-columns: subgrid; /* inherit parent's columns */
}
The subgrid admits substantial alignment of nested grid children with the parent.
Centred page
.page {
display: grid;
place-items: center;
min-height: 100vh;
}
The place-items: center admits both horizontal and vertical centring.
Dashboard
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 1rem;
}
.widget-1 { grid-column: span 6; }
.widget-2 { grid-column: span 3; }
.widget-3 { grid-column: span 3; }
.widget-large { grid-column: span 12; }
The 12-column grid admits substantial flexibility — substantial parallel to traditional grid frameworks.
Container queries
Container queries admit responsive design based on parent size:
.card {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card__title {
font-size: 1.5rem;
}
}
@container (min-width: 600px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
The mechanism admits substantial component-driven responsive design — substantial improvement over media-query-only approaches.
Choosing Flexbox vs Grid
The conventional discipline:
- Flexbox — for one-dimensional layout (single row or column).
- Grid — for two-dimensional layout (rows and columns simultaneously).
- Flexbox — when items have variable sizes and should adapt to content.
- Grid — when overall layout structure matters; substantial alignment across both axes.
Examples:
| Use | Flexbox | Grid |
|---|---|---|
| Navigation bar | ✓ | |
| Button group | ✓ | |
| Card row | ✓ | |
| Page layout | ✓ | |
| Dashboard | ✓ | |
| Image gallery | ✓ | |
| Form layout | ✓ | |
| Sidebar + main | ✓ | ✓ |
Often both are used together — Grid for page structure, Flexbox for components within.
Common patterns
Centring (multiple methods)
/* Flexbox: */
.center {
display: flex;
justify-content: center;
align-items: center;
}
/* Grid: */
.center {
display: grid;
place-items: center;
}
/* Margin auto: */
.center {
width: 800px;
margin: 0 auto; /* horizontal only */
}
Two-column with stack on mobile
.layout {
display: grid;
gap: 1rem;
grid-template-columns: 1fr; /* stacked default */
}
@media (min-width: 768px) {
.layout {
grid-template-columns: 250px 1fr; /* sidebar + main */
}
}
Equal-height cards
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.card {
display: flex;
flex-direction: column;
}
.card__body {
flex: 1; /* push footer to bottom */
}
Sticky header with grid
.layout {
display: grid;
grid-template-rows: auto 1fr;
min-height: 100vh;
}
.header {
position: sticky;
top: 0;
z-index: 10;
background: white;
}
Masonry-like layout
CSS Grid does not natively admit masonry until Grid Level 3; the conventional substitute uses Flexbox columns:
.masonry {
columns: 250px; /* multi-column layout */
column-gap: 1rem;
}
.masonry > * {
margin-bottom: 1rem;
break-inside: avoid; /* don't split items */
}
Holy Grail (modern)
body {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
main {
display: grid;
grid-template-columns: 200px 1fr 200px;
gap: 1rem;
}
@media (max-width: 768px) {
main {
grid-template-columns: 1fr;
}
}
Magazine layout
.article {
display: grid;
grid-template-columns: 1fr min(65ch, 100%) 1fr;
}
.article > * {
grid-column: 2; /* default to centre column */
}
.article > .full-bleed {
grid-column: 1 / -1; /* full width */
}
The pattern admits substantial readable text width with full-bleed images.
Auto-grid utility
.auto-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--min-size, 250px)), 1fr));
gap: var(--gap, 1rem);
}
<div class="auto-grid" style="--min-size: 200px; --gap: 0.5rem;">
<!-- items -->
</div>
A note on the conventional discipline
The contemporary CSS layout advice:
- Use Flexbox for one-dimensional layouts.
- Use Grid for two-dimensional layouts.
- Use
gapover margins for spacing in flex/grid. - Use
repeat(auto-fit, minmax(...))for responsive grids. - Use named
grid-template-areasfor substantial readable layout. - Use container queries for component-level responsive design.
- Use
min-height: 100vh(or100dvh) for full-viewport sections. - Use
place-items: centerfor substantial centring. - Use logical properties (
block/inline) for internationalisation. - Use Grid for page structure, Flexbox for components — they compose well.
The combination — Flexbox for one-axis, Grid for two-axis, the substantial alignment properties, container queries for component-level responsiveness, the subgrid for substantial nested alignment — is the substance of CSS’s modern layout surface. The discipline produces substantial responsive layouts with substantial declarative control over spatial arrangement.