Difficulty: Intermediate
Grid template areas provide a visual, ASCII-art-like way to define your grid layout. Instead of placing items using line numbers, you define named regions in the grid and assign items to those regions. This approach is arguably the most readable way to define page layouts in CSS because the grid-template-areas property visually represents the layout structure.
The grid-template-areas property uses a string for each row, where each word in the string represents a named area. All strings must have the same number of words (matching the column count). An area name can span multiple cells by repeating it across adjacent cells in the same row or adjacent rows. A period (.) represents an empty cell. For example, a three-column, three-row layout might look like: 'header header header' 'sidebar main main' 'footer footer footer'.
The grid-area property on a grid item assigns it to a named area. The value must exactly match one of the area names defined in grid-template-areas. When you assign an item to an area, it fills the entire region defined by that name in the template, regardless of how many cells the area spans. This is more intuitive than calculating grid-column and grid-row values.
Named areas must form rectangles. You cannot create an L-shaped or T-shaped area. Each area name must form a contiguous rectangular block in the template. If an area name appears in non-contiguous cells or in a non-rectangular pattern, the CSS is invalid and the layout breaks. This is the most common mistake when working with grid-template-areas.
Grid template areas pair beautifully with media queries for responsive layouts. You can define entirely different area arrangements at different breakpoints by rewriting the grid-template-areas value. The HTML structure stays the same, but the visual layout transforms completely. For example, a three-column desktop layout can become a single-column mobile layout by stacking all areas vertically in the mobile template.
.page {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
min-height: 100vh;
gap: 0;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
The grid-template-areas property visually maps out the layout. Each quoted string is a row. 'header header' means the header spans both columns. Items are assigned to areas using grid-area with the matching name.
.dashboard {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: auto 300px 200px;
grid-template-areas:
"stats stats chart chart"
"table table chart chart"
"feed feed feed feed";
gap: 20px;
padding: 20px;
}
.stats-widget { grid-area: stats; }
.chart-widget { grid-area: chart; }
.table-widget { grid-area: table; }
.feed-widget { grid-area: feed; }
The dashboard layout uses a 4-column grid with named areas. The chart spans 2 columns and 2 rows (a 2x2 block). The feed spans the full width. The ASCII-art template makes the layout immediately understandable.
.app {
display: grid;
gap: 16px;
min-height: 100vh;
}
.app-header { grid-area: header; }
.app-nav { grid-area: nav; }
.app-main { grid-area: main; }
.app-aside { grid-area: aside; }
.app-footer { grid-area: footer; }
/* Desktop: 3-column holy grail */
@media (min-width: 1024px) {
.app {
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
}
/* Tablet: 2-column */
@media (min-width: 768px) and (max-width: 1023px) {
.app {
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto auto;
grid-template-areas:
"header header"
"nav main"
"aside aside"
"footer footer";
}
}
/* Mobile: single column */
@media (max-width: 767px) {
.app {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
}
The same HTML structure adapts to three different layouts using only CSS changes. On desktop, it is a 3-column holy grail layout. On tablet, the aside moves below the main content. On mobile, everything stacks in a single column. The grid-area assignments on the items never change.
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 200px 200px 200px;
grid-template-areas:
"hero hero sidebar"
"hero hero ."
"thumb1 thumb2 thumb3";
gap: 16px;
}
.hero { grid-area: hero; }
.sidebar { grid-area: sidebar; }
.thumb1 { grid-area: thumb1; }
.thumb2 { grid-area: thumb2; }
.thumb3 { grid-area: thumb3; }
A period (.) represents an empty cell. In this gallery layout, the hero image spans a 2x2 area, the sidebar occupies one cell, and the cell below the sidebar is intentionally left empty. The bottom row has three thumbnails.
grid-template-areas, Named Areas, grid-area, Complex Layouts