CSS Grid
CSS Grid is the most powerful layout system in CSS. Unlike Flexbox (one-dimensional — a row or a column), Grid is two-dimensional — it controls both rows and columns at the same time. It's perfect for full-page layouts, dashboard grids, photo galleries, and any design with an explicit two-axis structure. Flexbox and Grid work beautifully together — use Grid for the big picture, Flexbox for the details inside.
Grid Fundamentals
Like Flexbox, CSS Grid requires a container with display: grid. Its direct children become grid items that automatically place themselves into the defined rows and columns.
The most important property is grid-template-columns — it defines how many columns you have and how wide they are.
.grid { display: grid; grid-template-columns: 1fr 1fr 1fr; /* 3 equal columns */ gap: 1rem; } /* Shorthand for 3 equal columns: */ .grid { display: grid; grid-template-columns: repeat(3, 1fr); /* same as 1fr 1fr 1fr */ gap: 1rem; }
fr stands for "fractional unit" — it represents a fraction of the available space in the grid container. 1fr 2fr 1fr creates 3 columns where the middle one is twice as wide as the others. Mix fr with fixed units: 200px 1fr gives you a fixed sidebar and a fluid main content area.Rows, Columns & Gap
Define both axes explicitly with grid-template-columns and grid-template-rows. The gap property (or column-gap / row-gap separately) adds gutters between cells.
.layout { display: grid; grid-template-columns: 200px 1fr 1fr; /* sidebar + 2 equal cols */ grid-template-rows: 80px 1fr 60px; /* header, content, footer */ gap: 1rem; /* gap between all cells */ min-height: 100vh; } /* Separate row/column gaps: */ .grid { row-gap: 2rem; column-gap: 1rem; }
| Property | Example | What it does |
|---|---|---|
| grid-template-columns | repeat(3, 1fr) | Defines column track sizes |
| grid-template-rows | 80px 1fr 60px | Defines row track sizes |
| gap | 1rem · 1rem 2rem | Space between rows and columns |
| auto-fill | repeat(auto-fill, minmax(200px, 1fr)) | Fills row with as many columns as fit |
| auto-fit | repeat(auto-fit, minmax(200px, 1fr)) | Like auto-fill but collapses empty tracks |
| minmax() | minmax(200px, 1fr) | Column is at least 200px, at most 1fr |
Spanning Columns & Rows
Grid items can span multiple columns or rows. This is where Grid becomes magical — you can create magazine-style layouts where some items are larger than others.
/* Method 1: span keyword */ .feature-card { grid-column: span 2; } /* spans 2 columns */ .tall-card { grid-row: span 2; } /* spans 2 rows */ /* Method 2: line numbers (1-indexed) */ .hero { grid-column: 1 / 4; /* from line 1 to line 4 = full width of 3-col grid */ grid-row: 1 / 3; /* spans 2 rows */ } /* -1 means "last line" */ .full-width { grid-column: 1 / -1; } /* always spans full width */
(span 2)
Named Grid Areas
Named grid areas are one of the most powerful CSS features ever made. You draw your layout as ASCII art in the CSS, then assign elements to areas by name. It's incredibly readable and maintainable.
/* CSS */ .page { display: grid; grid-template-areas: "header header header" "sidebar main main " "footer footer footer"; grid-template-columns: 200px 1fr 1fr; grid-template-rows: 80px 1fr 60px; gap: 1rem; min-height: 100vh; } header { grid-area: header; } aside { grid-area: sidebar; } main { grid-area: main; } footer { grid-area: footer; } /* HTML */ <div class="page"> <header>Header</header> <aside>Sidebar</aside> <main>Main Content</main> <footer>Footer</footer> </div>
grid-template-areas, use a dot to leave a cell empty: "sidebar . main" puts nothing in the middle column. Multiple dots can be used: ".. main". This is useful for asymmetric layouts.Responsive Grid: auto-fill & minmax()
One of Grid's killer features is creating responsive multi-column layouts without any media queries. The combination of repeat(auto-fill, minmax()) is a one-liner that auto-adapts from 1 column to many.
/* auto-fill: fills row with as many 250px columns as fit */ .card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1.5rem; } /* On a 1200px container: 4 columns (each ~275px) On a 800px container: 3 columns (each ~245px → wraps) On a 400px container: 1 column ALL automatic! */ /* auto-fit vs auto-fill: auto-fill: keeps empty column tracks (whitespace) auto-fit: collapses empty tracks (items stretch to fill) → For fluid responsive grids, use auto-fit */ .fluid-grid { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
auto-fit so a lone last-row item doesn't become comically huge.repeat(3, 1fr) produce?grid-template-areas let you do?repeat(auto-fit, minmax(200px, 1fr)) achieve?1. A
.dashboard grid with 3 columns (240px 1fr 1fr) and 4 rows (70px 180px 180px 1fr)2. Named areas: header spanning all 3 columns, sidebar spanning rows 2–4, stat1 and stat2 for the top right 2 cells, chart spanning 2 columns on row 3, and table filling row 4 right side
3. Assign each child element to its area with
grid-area4. Add
gap: 1rem and give each area a distinct background color with border-radius5. Bonus: Add
min-height: 100vh and make the sidebar sticky or visually distinct
💡 Show hints
- Start with:
grid-template-areas: "header header header" "sidebar stat1 stat2" "sidebar chart chart" "sidebar table table" - Sidebar:
grid-area: sidebar;— it will automatically span rows because the template says so - Each stat card:
grid-area: stat1;andgrid-area: stat2; - Use
display: flex; align-items: center; justify-content: center;inside each grid area for centered content - Add padding to each area and use border-radius for polished look
* { box-sizing: border-box; margin: 0; padding: 0; } body { background: #05091a; color: #eef3ff; font-family: sans-serif; } .dashboard { display: grid; grid-template-areas: "header header header" "sidebar stat1 stat2 " "sidebar chart chart " "sidebar table table "; grid-template-columns: 240px 1fr 1fr; grid-template-rows: 70px 160px 200px 1fr; gap: 1rem; min-height: 100vh; padding: 1rem; } .d-header { grid-area: header; background: #0a1230; } .d-sidebar { grid-area: sidebar; background: #0a1230; } .d-stat1 { grid-area: stat1; background: rgba(79,158,255,.1); } .d-stat2 { grid-area: stat2; background: rgba(45,232,192,.1); } .d-chart { grid-area: chart; background: rgba(167,139,250,.08); } .d-table { grid-area: table; background: rgba(251,191,36,.08); } /* All areas: */ [class^="d-"] { border-radius: 12px; border: 1px solid rgba(255,255,255,.08); padding: 1rem; display: flex; align-items: center; justify-content: center; font-weight: 600; }