The ultimate two-dimensional layout solution. From Grid fundamentals to responsive best practices, master the core of modern CSS layout.
CSS Grid is the first truly two-dimensional layout system. Unlike Flexbox, which handles a single axis (row or column), Grid can control both rows and columns simultaneously, making complex layouts simple and intuitive. This guide covers Grid's core concepts, real-world patterns, and how to choose between Grid and Flexbox.
.grid-container {
display: grid;
grid-template-columns: 200px 200px 200px; /* Three equal columns */
grid-template-rows: 100px 100px; /* Two equal rows */
gap: 16px;
}
fr (fraction) is Grid's unique flexible unit, representing equal shares of remaining space:
/* Three equal columns */
grid-template-columns: 1fr 1fr 1fr;
/* Sidebar + main content */
grid-template-columns: 250px 1fr;
/* Complex ratio */
grid-template-columns: 2fr 1fr 1fr; /* 2:1:1 */
/* Mixed fixed and flexible */
grid-template-columns: 200px 1fr 200px;
/* Equivalent to 1fr 1fr 1fr 1fr */
grid-template-columns: repeat(4, 1fr);
/* Repeating pattern */
grid-template-columns: repeat(3, 1fr 2fr); /* 1fr 2fr 1fr 2fr 1fr 2fr */
/* auto-fill responsive */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
This is one of the most confusing concepts in Grid. Both work with minmax() to create responsive column counts:
/* auto-fill: preserves empty tracks */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* auto-fit: collapses empty tracks, items stretch to fill */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
auto-fit works better—items stretch when few and wrap when many. Use auto-fill when you need items to maintain a fixed width.One of Grid's most powerful features is named areas, which let you define layouts with intuitive "ASCII art" syntax:
.page-layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
grid-template-columns: 250px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 1rem;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
Named areas make layout code as intuitive as "drawing"—easy to read, maintain, and modify.
/* Span 2 columns */
.featured { grid-column: span 2; }
/* Span 2 rows */
.sidebar { grid-row: span 2; }
/* Specify exact position */
.highlight {
grid-column: 1 / 3; /* From line 1 to line 3 */
grid-row: 2 / 4; /* From line 2 to line 4 */
}
Grid's alignment properties are similar to Flexbox but with two dimensions:
.grid-container {
/* Item alignment within cells */
justify-items: center; /* Horizontal */
align-items: center; /* Vertical */
place-items: center; /* Shorthand: both directions */
/* Grid alignment within container */
justify-content: center; /* Horizontal */
align-content: center; /* Vertical */
place-content: center; /* Shorthand */
}
/* Individual item alignment */
.special-item {
justify-self: end;
align-self: start;
place-self: end start; /* Shorthand */
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
padding: 1.5rem;
}
/* No media queries needed! Automatically adapts:
Large screen: 4–5 columns
Medium screen: 2–3 columns
Small screen: 1 column
*/
/* Default: single column (mobile) */
.layout {
display: grid;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
gap: 1rem;
}
/* Tablet and above */
@media (min-width: 768px) {
.layout {
grid-template-areas:
"header header"
"nav main"
"aside main"
"footer footer";
grid-template-columns: 200px 1fr;
}
}
/* Desktop and above */
@media (min-width: 1024px) {
.layout {
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
grid-template-columns: 200px 1fr 250px;
}
}
/* Limit column width range */
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
/* Use clamp for gap control */
gap: clamp(0.5rem, 2vw, 2rem);
/* max() ensures sidebar doesn't shrink below a threshold */
grid-template-columns: max(200px, 20%) 1fr;
Subgrid allows child elements to inherit the parent grid's track definitions, enabling cross-level alignment:
.parent-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.child-card {
grid-column: span 3;
display: grid;
grid-template-columns: subgrid; /* Inherits parent's 3 columns */
}
/* Elements inside child-card auto-align with parent columns */
/* Grid controls page structure */
.page {
display: grid;
grid-template-columns: 280px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
}
/* Flexbox handles component internals */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
}
.card-body {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
When items don't fill the container, auto-fill preserves empty grid tracks (placeholders), while auto-fit collapses empty tracks to 0 width, stretching items to fill the space. When items are sufficient to fill the container, both produce identical results.
Not entirely. Grid excels at two-dimensional layout (controlling rows and columns simultaneously), while Flexbox excels at one-dimensional layout (arranging content in a single row or column). Best practice is to use both together: Grid for page structure, Flexbox for component internals.