Advanced Grid Patterns
Once you know the grid basics, a handful of advanced patterns unlock layouts that used to require JavaScript or brittle hacks: masonry-style galleries, overlapping elements, full-bleed article layouts, magazine spreads, and self-adjusting responsive grids. This page collects the patterns worth memorizing.
The RAM Pattern (Repeat, Auto, Minmax)
The single most useful responsive-grid trick: columns that add and remove themselves based on available width, with no media queries.
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
gap: 1rem;
}
/* - auto-fit: create as many columns as fit, collapse empties
- minmax(250px, 1fr): each at least 250px, share the rest
- min(250px, 100%): never overflow a container under 250px */Masonry-style Layouts
True masonry (grid-template-rows: masonry) is still not broadly shipped, but two approximations work everywhere today.
/* Approach 1: small row units + spans (real grid, keeps order) */
.masonry {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
grid-auto-rows: 8px; /* tiny row rhythm */
gap: 0 16px;
}
.masonry > * {
/* each item spans enough 8px rows for its content;
usually set from JS: span = ceil(height / 8) */
grid-row: span 24;
}
/* Approach 2: CSS multi-columns (no JS, but ordering runs
down each column instead of across rows) */
.masonry-cols {
columns: 4 220px;
column-gap: 16px;
}
.masonry-cols > * {
break-inside: avoid;
margin-bottom: 16px;
}Overlapping Grid Items
Grid items can occupy the same cells — overlap is a first-class feature, not a hack. Control stacking with z-index (grid items form stacking order without needing positioning).
.hero {
display: grid;
grid-template: 1fr / 1fr; /* one cell */
}
.hero > img,
.hero > .caption {
grid-area: 1 / 1; /* both in the same cell → overlap */
}
.hero > .caption {
align-self: end;
z-index: 1;
padding: 2rem;
background: linear-gradient(transparent, rgb(0 0 0 / 0.7));
color: white;
}/* Partial overlap: a card that rides over the banner */
.profile {
display: grid;
grid-template-rows: 160px 40px auto;
}
.banner { grid-row: 1 / 3; grid-column: 1; }
.avatar { grid-row: 2 / 4; grid-column: 1; justify-self: center; }Full-Bleed Article Layout
Prose constrained to a readable measure, while images and code blocks can "break out" to the full viewport width — all children stay in normal flow.
.article {
display: grid;
grid-template-columns:
[full-start] minmax(1rem, 1fr)
[content-start] min(65ch, 100%) [content-end]
minmax(1rem, 1fr) [full-end];
}
.article > * { grid-column: content; } /* default: readable column */
.article > .full-bleed {
grid-column: full; /* edge to edge */
}Named Grid Lines and Areas
/* Named lines: [name] before each track */
.layout {
display: grid;
grid-template-columns:
[sidebar-start] 240px
[sidebar-end main-start] 1fr
[main-end];
}
.sidebar { grid-column: sidebar; } /* name without -start/-end */
/* Named areas define lines implicitly too:
area "main" creates main-start / main-end lines */
.page {
grid-template-areas:
"nav main"
"nav footer";
}
.ad { grid-row: main-start / footer-end; } /* span using implicit names */foo-start and foo-end implicitly creates an area called foo, and vice versa. Pick whichever declaration style reads better and mix freely.Dense Packing
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
grid-auto-rows: 140px;
grid-auto-flow: dense; /* backfill the holes */
gap: 8px;
}
.gallery .wide { grid-column: span 2; }
.gallery .tall { grid-row: span 2; }
.gallery .big { grid-column: span 2; grid-row: span 2; }dense reorders items visually to fill gaps, so visual order no longer matches DOM (and tab) order. Fine for decorative galleries; avoid it for interactive content where keyboard users would jump around unpredictably.Subgrid Use Cases
subgrid lets a nested grid adopt its parent's tracks, so content in sibling cards lines up — headers, bodies, and buttons align across a row even when text lengths differ.
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1rem;
}
.card {
display: grid;
grid-row: span 3; /* title, body, action rows */
grid-template-rows: subgrid; /* share the parent's rows */
gap: 0.5rem;
}
/* Now every .card's button sits on the same baseline row,
no matter how long each card's text is. */Magazine Layout
.spread {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-auto-rows: minmax(120px, auto);
gap: 1rem;
}
.feature { grid-column: 1 / 5; grid-row: 1 / 3; }
.headline { grid-column: 5 / 7; grid-row: 1; }
.pullquote { grid-column: 5 / 7; grid-row: 2; }
.story-a { grid-column: 1 / 3; }
.story-b { grid-column: 3 / 5; }
.story-c { grid-column: 5 / 7; }
@media (max-width: 700px) {
.spread > * { grid-column: 1 / -1 !important; grid-row: auto; }
}Pattern Selection Guide
You need… | Pattern |
|---|---|
Responsive columns, no media queries | RAM: |
Pinterest-style variable-height gallery | Multi-columns, or row-span masonry |
Text over an image, in flow | Same-cell overlap ( |
Readable prose + edge-to-edge media | Full-bleed named-line grid |
Aligned content across sibling cards | Subgrid rows |
Mixed-size tiles with no holes |
|
Editorial/asymmetric layout | Explicit line placement on a 6/12-col grid |
Combine patterns freely: a full-bleed article grid can contain a RAM card grid which uses subgrid rows internally.
Prefer
gapover margins inside grids — margins do not collapse and fight the track sizing.Use Firefox or Chrome DevTools grid overlays to see line numbers and names while building these.
Related pages: Grid cheatsheet, Subgrid, Named grid lines, and repeat() and auto-fill.