CSS Grid Layout is a two-dimensional layout system for the web. It lets you control columns and rows at the same time, which makes it ideal for page layouts, dashboards, galleries, forms, tl-card collections, magazine layouts, and any design where items need to line up in both directions.
Grid is different from older layout techniques because the layout can be defined on the parent container. Instead of forcing every child element to manage its own position with floats, margins, or absolute positioning, Grid lets the tl-container describe the structure and then places items into that structure.
A grid layout starts with a grid container. The direct children of that tl-container become grid items. Grid properties can be divided into tl-container properties and item properties.
<div class="grid">
<article class="tl-card">One</article>
<article class="tl-card">Two</article>
<article class="tl-card">Three</article>
<article class="tl-card">Four</article>
</div>
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.card {
padding: 1rem;
background: #e0f2fe;
border: 1px solid #7dd3fc;
}
Before using Grid deeply, it helps to understand the words used in Grid documentation and browser DevTools.
| Term | Meaning |
|---|---|
| Grid container | The parent element with display: grid or display: inline-grid. |
| Grid item | A direct child of the grid container. |
| Grid line | The dividing line between rows or columns. Lines are numbered starting from 1. |
| Grid track | A tl-row or column between two grid lines. |
| Grid cell | The space where one tl-row and one column intersect. |
| Grid area | A rectangular area made from one or more grid cells. |
| Explicit grid | Rows and columns you define with template properties. |
| Implicit grid | Extra rows or columns the browser creates when items do not fit the explicit grid. |
The most important Grid properties are grid-template-columns and grid-template-rows. They define the structure of the grid.
.fixed-columns {
display: grid;
grid-template-columns: 200px 200px 200px;
}
.equal-columns {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.mixed-columns {
display: grid;
grid-template-columns: 220px 1fr 2fr;
}
.defined-rows {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 80px 200px 80px;
}
.template-shorthand {
display: grid;
grid-template: 80px 1fr 60px / 240px 1fr;
}
The fr unit means a fraction of the available space. It is one of the main reasons Grid is pleasant to use. After fixed-width columns, gaps, and content constraints are calculated, the remaining space is divided among fr tracks.
.three-equal-columns {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.sidebar-and-content {
display: grid;
grid-template-columns: 260px 1fr;
}
.weighted-columns {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
/* Middle column receives twice as much free space. */
}
Grid has layout functions that reduce repetition and make responsive layouts easier. The most useful combination is repeat(auto-fit, minmax(...)), which creates as many columns as can fit without needing a media query.
<section class="product-grid">
<article>Product 1</article>
<article>Product 2</article>
<article>Product 3</article>
<article>Product 4</article>
</section>
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1.25rem;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 0.75rem;
}
| Function or Keyword | Use |
|---|---|
repeat(3, 1fr) | Creates three equal tracks without writing 1fr three times. |
minmax(240px, 1fr) | Sets a track minimum and maximum size. |
auto-fit | Collapses empty tracks and stretches existing items. |
auto-fill | Keeps empty tracks in the tl-row when extra space exists. |
Use gap to control space between rows and columns. It is cleaner than adding margins to grid items because it only affects the space between tracks.
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.different-row-and-column-gaps {
display: grid;
row-gap: 1rem;
column-gap: 2rem;
}
.gap-shorthand {
display: grid;
gap: 1rem 2rem;
/* tl-row gap, then column gap */
}
Grid lines are numbered. A three-column grid has four vertical lines: line 1 before the first column, line 2 between the first and second columns, line 3 between the second and third columns, and line 4 after the third column.
.layout {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 120px);
gap: 1rem;
}
.featured {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
.wide {
grid-column: 2 / span 3;
}
.last-column {
grid-column: 4;
grid-row: 1 / span 2;
}
Named grid areas let you describe a page layout visually in CSS. This is one of the clearest ways to build major page regions such as header, sidebar, main content, and footer.
<div class="page">
<header class="site-header">Header</header>
<aside class="sidebar">Sidebar</aside>
<main class="content">Content</main>
<footer class="site-footer">Footer</footer>
</div>
.page {
min-height: 100vh;
display: grid;
grid-template-columns: 260px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
}
.site-header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.site-footer { grid-area: footer; }
@media (max-width: 768px) {
.page {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"content"
"sidebar"
"footer";
}
}
Grid has alignment properties for items inside their cells and for the whole grid inside its container. The place-* properties are shorthands that set both tl-row and column alignment.
| Property | Applies To | Purpose |
|---|---|---|
justify-items | Container | Aligns all items horizontally inside their cells. |
align-items | Container | Aligns all items vertically inside their cells. |
place-items | Container | Shorthand for align-items and justify-items. |
justify-content | Container | Aligns the whole grid horizontally when there is extra space. |
align-content | Container | Aligns the whole grid vertically when there is extra space. |
justify-self | Item | Aligns one item horizontally inside its cell. |
align-self | Item | Aligns one item vertically inside its cell. |
.grid {
display: grid;
grid-template-columns: repeat(3, 120px);
grid-template-rows: repeat(2, 100px);
gap: 1rem;
justify-content: center;
align-content: center;
place-items: center;
min-height: 400px;
}
.special-item {
justify-self: stretch;
align-self: end;
}
If you define three columns but have more items than fit in one row, the browser creates extra rows automatically. Those extra rows are part of the implicit grid. You can control their size with grid-auto-rows and the placement direction with grid-auto-flow.
.auto-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(120px, auto);
gap: 1rem;
}
.column-flow {
display: grid;
grid-template-rows: repeat(3, 120px);
grid-auto-flow: column;
grid-auto-columns: 220px;
}
.dense-layout {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: dense;
}
A responsive tl-card grid is one of the most common Grid patterns. It can usually be built without media queries by combining repeat(), auto-fit, and minmax().
<section class="cards">
<article class="tl-card">
<h4>Starter</h4>
<p>For small projects.</p>
</article>
<article class="tl-card">
<h4>Team</h4>
<p>For growing teams.</p>
</article>
<article class="tl-card">
<h4>Enterprise</h4>
<p>For large organizations.</p>
</article>
</section>
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}
.card {
display: grid;
gap: 0.5rem;
padding: 1rem;
border: 1px solid #d1d5db;
border-radius: 8px;
}
Grid is very useful for dashboards because panels can span different rows and columns while still sharing one consistent layout system.
<main class="dashboard">
<section class="panel revenue">Revenue</section>
<section class="panel users">Users</section>
<section class="panel chart">Chart</section>
<section class="panel activity">Activity</section>
</main>
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 140px;
gap: 1rem;
}
.revenue { grid-column: span 2; }
.users { grid-column: span 2; }
.chart {
grid-column: span 3;
grid-row: span 2;
}
.activity { grid-row: span 2; }
@media (max-width: 800px) {
.dashboard {
grid-template-columns: 1fr;
}
.revenue,
.users,
.chart,
.activity {
grid-column: auto;
grid-row: auto;
}
}
The classic holy grail layout has a header, footer, main content area, and sidebars. Grid can express this layout directly, including a mobile version.
.holy-grail {
min-height: 100vh;
display: grid;
grid-template:
"header header header" auto
"left main right" 1fr
"footer footer footer" auto
/ 220px minmax(0, 1fr) 220px;
}
.header { grid-area: header; }
.left-sidebar { grid-area: left; }
.main { grid-area: main; }
.right-sidebar { grid-area: right; }
.footer { grid-area: footer; }
@media (max-width: 900px) {
.holy-grail {
grid-template:
"header" auto
"main" 1fr
"left" auto
"right" auto
"footer" auto
/ 1fr;
}
}
auto-fit and auto-fill are similar, but they behave differently when there is extra room. In most responsive tl-card layouts, auto-fit is the better starting choice because it collapses empty tracks and lets existing cards stretch.
| Keyword | Behavior | Common Use |
|---|---|---|
auto-fit | Empty tracks collapse and filled tracks stretch. | Responsive cards, product grids, feature grids. |
auto-fill | Empty tracks remain in the layout. | Layouts where reserved empty columns are useful. |
Grid and Flexbox work very well together. Use Grid when the layout needs rows and columns. Use Flexbox when a component mainly flows in one direction.
| Feature | CSS Grid | Flexbox |
|---|---|---|
| Layout type | Two-dimensional | One-dimensional |
| Best for | Pages, dashboards, galleries, full layouts | Navbars, toolbars, button groups, form rows |
| Control style | Container defines rows and columns | Items flow along one main axis |
| Item placement | Items can be placed in exact cells or areas | Items usually follow source order |
subgrid allows a nested grid to use the tl-row or column tracks of its parent grid. It is helpful when nested content must align with the outer layout. Browser support is now strong in modern browsers, but always check your target browser requirements before relying on it.
.pricing-table {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.plan {
display: grid;
grid-template-rows: subgrid;
grid-row: span 4;
}
When a grid does not behave as expected, inspect the grid overlay in browser DevTools. It can show line numbers, track sizes, gaps, and named areas.
display: grid is on the parent container.minmax(0, 1fr) or min-width: 0 when content overflows flexible columns.grid-template-areas has the same number of columns.gap instead of margins when spacing grid tracks.CSS Grid is the main layout tool for two-dimensional design on the web. It gives you direct control over rows, columns, gaps, placement, alignment, responsive tracks, and named regions. It removes many old layout workarounds and makes complex layouts easier to read and maintain.
To master Grid, start with display: grid, grid-template-columns, gap, and the fr unit. Then practice item placement, named grid areas, responsive minmax() patterns, and DevTools debugging. Once these pieces are comfortable, Grid becomes a reliable foundation for modern page layout.
Apply grid-template-columns to a child item
Apply grid-template-columns to the grid container
Use margins between grid items
Use gap on the grid container
Write uneven grid-template-areas rows
Make every grid-template-areas tl-row contain the same number of cells
Use Grid for a simple one-direction button row
Use Flexbox for simple one-dimensional component layouts
Assume 1fr can always shrink below content width
Use minmax(0, 1fr) or min-width: 0 when content overflows
display: grid creates a grid container, and its direct children become grid items.
grid-template-columns and grid-template-rows define the grid structure.
fr distributes available space across flexible tracks.
repeat(auto-fit, minmax(240px, 1fr)) is a powerful responsive grid pattern.
grid-column and grid-row place or span items using line numbers.
grid-template-areas creates readable named page regions.
gap is the best way to create space between grid tracks.
Explore 500+ free tutorials across 20+ languages and frameworks.