This episode covers CSS Grid for two-dimensional layout: defining rows and columns with grid-template, the fr unit and the repeat function, placing items with grid lines, and named areas for a clear page structure.

Flexbox solves one-dimensional layout. But for pages that need rows and columns at the same time — dashboards, galleries, news pages — you need CSS Grid. Grid works on two axes at once, dividing space into row tracks and column tracks. Grid isn't a replacement for Flexbox; the two complement each other. A rule of thumb: use Flexbox to arrange items in a single row or column, and Grid for two-dimensional structures where items fill rows and columns simultaneously. Why does it matter? Grid reduces the need for many wrapper classes and negative-margin tricks. With Grid, the layout structure is expressed directly in CSS — easier to read, maintain, and make responsive.
display: grid on an element makes it a grid container. Column tracks are defined with grid-template-columns, and rows with grid-template-rows:
.layout {
display: grid;
grid-template-columns: 200px 1fr 1fr;
gap: 16px;
}The code above creates three columns: the first at 200px, the other two sharing the remaining space equally. The fr (fraction) value divides the free space left after fixed-size tracks are calculated, similar to the flex-grow concept in Flexbox.
For uniform columns, use repeat():
.galeri {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.auto-fill {
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}repeat(3, 1fr) creates three equal-width columns. The auto-fill pattern with minmax(180px, 1fr) makes columns adapt to the container width — Grid automatically adds or removes columns.
Each track has grid lines as its boundaries. Items can be placed from a start line to an end line using grid-column and grid-row:
.header {
grid-column: 1 / -1;
}
.sidebar {
grid-column: 1 / 2;
grid-row: 2 / 4;
}
.konten {
grid-column: 2 / -1;
}The value 1 / -1 means from the first line to the last line — the item stretches across the entire row. -1 refers to the very last line, so it works without knowing the exact column count.
As layouts get more complex, named areas make the structure far clearer:
.halaman {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar konten"
"footer footer";
min-height: 100vh;
gap: 12px;
}
.header {
grid-area: header;
}
.sidebar {
grid-area: sidebar;
}
.konten {
grid-area: konten;
}
.footer {
grid-area: footer;
}grid-template-areas describes the layout like a text map. Each string row represents one grid row; the same name repeated means the item stretches across. Structures like this are very easy to read and modify.
Grid uses the same alignment properties as Flexbox, but applies them on both axes at once:
.grid {
display: grid;
grid-template-columns: repeat(3, 120px);
justify-content: center;
align-content: center;
height: 100vh;
gap: 16px;
}justify-content and align-content align the whole group of tracks within the container. To align items within their own cells, use justify-items and align-items.
.sel {
justify-items: stretch;
align-items: start;
}The default stretch makes items fill their cell. Changing it to start or center gives you control over an item's position inside its cell.
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Grid Berita</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="halaman">
<header class="header">Berita Hari Ini</header>
<aside class="sidebar">Topik Populer</aside>
<main class="konten">
<article class="kartu">Artikel utama</article>
<article class="kartu">Artikel kedua</article>
<article class="kartu">Artikel ketiga</article>
</main>
<footer class="footer">Hak cipta 2026</footer>
</div>
</body>
</html>* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, sans-serif; }
.halaman { display: grid; grid-template-columns: 220px 1fr; grid-template-areas: "header header" "sidebar konten" "footer footer"; min-height: 100vh; gap: 12px; padding: 12px; }
.header, .sidebar, .konten, .footer { padding: 16px; border-radius: 8px; }
.header { grid-area: header; background-color: #0f172a; color: white; }
.sidebar { grid-area: sidebar; background-color: #e2e8f0; }
.konten { grid-area: konten; display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
.kartu { background-color: white; border: 1px solid #cbd5e1; border-radius: 8px; padding: 16px; }
.footer { grid-area: footer; background-color: #f1f5f9; }Run npx serve . and observe how named areas lay out the header, sidebar, content, and footer. The nested grid inside konten creates cards that automatically adjust their column count to the available space.
Without explicit placement, Grid flows items in order. If two items stack, check whether grid-column or grid-row clashes, or use named areas to avoid ambiguity.
repeat(3, minmax(180px, 1fr)) works, but repeat(2, 1fr 2fr) is also valid. Avoid mixing fr with fixed values without reason so proportions stay predictable.
Grid doesn't replace Flexbox for arranging items in one row with full alignment. Use Grid for two dimensions and Flexbox for one — don't force either one.
Key takeaways:
grid-template-columns and grid-template-rows define tracks.fr unit divides free space; repeat() and auto-fill create dynamic columns.grid-column and grid-row place items using grid lines.grid-template-areas expresses the page structure visually.minmax() combined with auto-fit produces automatically responsive layouts.
In the next episode, episode 9, we'll cover responsive layout with media queries — adapting the display across different screen sizes with the right breakpoints.