Layouts: CSS Grid Basics

Layouts: CSS Grid Basics

CSS Grid is a two-dimensional layout system. It controls rows and columns at the same time.

Use Grid when you need:

  • page shells,
  • dashboards,
  • image galleries,
  • card grids,
  • complex forms,
  • magazine-style layouts,
  • or any layout where rows and columns both matter.

Flexbox asks, "How should items flow along one axis?" Grid asks, "What structure should this two-dimensional layout have?"


1. Grid Container and Grid Items

Grid starts with:

.container {
  display: grid;
}
<section class="container">
  <article>One</article>
  <article>Two</article>
  <article>Three</article>
</section>

The direct children become grid items.

Item 1Item 2Item 3Item 4Grid creates rows and columns for direct children.

2. Defining Columns and Rows

The core grid properties are:

.container {
  display: grid;
  grid-template-columns: 200px 1fr 100px;
  grid-template-rows: 100px auto;
  gap: 20px;
}

This creates:

  • three columns,
  • two rows,
  • and a 20px gap between tracks.

Grid tracks are rows or columns. Grid cells are the spaces where rows and columns intersect.


3. The fr Unit

fr means "fraction of available space."

.three-columns {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

This creates three equal columns.

.main-layout {
  display: grid;
  grid-template-columns: 240px 1fr;
}

The first column is fixed at 240px. The second receives the remaining space.

1fr1fr1frAvailable space is split into equal fractions.

4. repeat()

repeat() avoids repeating track definitions manually.

.grid {
  grid-template-columns: repeat(12, 1fr);
}

This is equivalent to:

.grid {
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

You can mix fixed and repeated tracks:

.layout {
  grid-template-columns: 240px repeat(3, 1fr);
}

5. minmax()

minmax(min, max) defines a track that cannot be smaller than the minimum or larger than the maximum.

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  gap: 1rem;
}

Each column is at least 200px, but can grow to share available space.

This is useful for card layouts because it prevents columns from becoming too narrow.


6. auto-fit and auto-fill

For responsive grids, combine repeat(), auto-fit, and minmax().

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
}

This creates as many columns as fit. When the screen gets smaller, the layout automatically reduces the number of columns.

wide: four columnsnarrow: two columns

auto-fit collapses empty tracks. auto-fill keeps empty tracks reserved. In practical card grids, auto-fit is often what you want.


7. Gap

gap controls space between rows and columns.

.grid {
  display: grid;
  gap: 1rem;
}

You can set row and column gaps separately:

.grid {
  row-gap: 2rem;
  column-gap: 1rem;
}

Or shorthand:

.grid {
  gap: 2rem 1rem;
}

The first value is row gap. The second is column gap.


8. Explicit and Implicit Grids

The explicit grid is what you define:

.grid {
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 120px 120px;
}

If there are more items than defined cells, the browser creates implicit rows or columns.

.grid {
  grid-auto-rows: minmax(120px, auto);
}

Use grid-auto-rows to control automatically created rows.

.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 180px;
  gap: 1rem;
}

9. Grid Lines

Grid lines are numbered. A three-column grid has four vertical column lines.

.feature {
  grid-column: 1 / 3;
}

This means the item starts at column line 1 and ends at column line 3.

.hero {
  grid-column: 1 / -1;
}

-1 means the last line, so this spans the full width.

grid-column: 1 / 31234Items can start and end on named or numbered lines.

10. Spanning

Use span when you care about how many tracks an item covers.

.wide {
  grid-column: span 2;
}
.tall {
  grid-row: span 2;
}

This is useful in dashboards, galleries, and content layouts.

.dashboard-card.featured {
  grid-column: span 2;
  grid-row: span 2;
}

11. Grid Template Areas

Template areas let you name parts of a layout.

.page {
  display: grid;
  grid-template-columns: 260px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}

.page-header {
  grid-area: header;
}

.page-sidebar {
  grid-area: sidebar;
}

.page-main {
  grid-area: main;
}

.page-footer {
  grid-area: footer;
}
headersidebarmainfooter

Template areas are readable and excellent for page-level layouts.


12. Responsive Template Areas

You can change the grid layout at breakpoints.

.page {
  display: grid;
  gap: 1rem;
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
}

@media (min-width: 800px) {
  .page {
    grid-template-columns: 260px 1fr;
    grid-template-areas:
      "header header"
      "sidebar main"
      "footer footer";
  }
}

This keeps mobile layout simple and expands into a two-column layout on larger screens.


13. Alignment in Grid

Grid has two levels of alignment.

Align Items Inside Cells

.grid {
  justify-items: center;
  align-items: center;
}
  • justify-items: horizontal alignment inside each cell.
  • align-items: vertical alignment inside each cell.

Align the Whole Grid

.grid {
  justify-content: center;
  align-content: center;
}
  • justify-content: moves the grid tracks horizontally when there is extra container space.
  • align-content: moves the grid tracks vertically when there is extra container space.

Align One Item

.special {
  justify-self: end;
  align-self: start;
}

Use self properties for one item.


14. Dense Packing

grid-auto-flow: dense lets the browser fill holes in the grid when later items fit.

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  grid-auto-flow: dense;
}

Be careful. Dense packing can visually reorder items. If the order matters for reading or accessibility, avoid dense packing.


15. Common Pattern: Responsive Card Grid

.course-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.25rem;
}
<section class="course-grid">
  <article>JavaScript</article>
  <article>TypeScript</article>
  <article>Python</article>
</section>

This is one of the most useful Grid patterns. It needs no media query for basic responsiveness.


16. Common Pattern: Holy Grail Layout

.app-shell {
  min-height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr auto;
}
<div class="app-shell">
  <header>Header</header>
  <main>Main content</main>
  <footer>Footer</footer>
</div>

The middle row grows to fill available space, pushing the footer to the bottom.


17. Common Pattern: Dashboard

.dashboard {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 1.5rem;
}

.metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
}

minmax(0, 1fr) prevents long content from forcing the main column wider than the viewport.

This is similar to using min-width: 0 in Flexbox.


18. Grid vs. Flexbox

Grid and Flexbox are complementary.

Layout problemRecommended tool
Navigation links in a rowFlexbox
Center icon and text in a buttonFlexbox
Responsive card galleryGrid
Full page header/sidebar/main/footerGrid
Toolbar with variable buttonsFlexbox
Form with aligned labels and fieldsGrid
Media object with image and textFlexbox

Grid can do one-dimensional layouts, and Flexbox can sometimes imitate grids, but using the right tool keeps CSS simpler.


19. Debugging Grid

When a grid layout behaves unexpectedly, ask:

  1. Which element has display: grid?
  2. Are the intended grid items direct children?
  3. What columns and rows are explicit?
  4. Are implicit rows being created?
  5. Is gap part of the available space calculation?
  6. Is an item spanning more tracks than expected?
  7. Are grid lines counted correctly?
  8. Would minmax(0, 1fr) prevent overflow?
  9. Is dense packing changing visual order?
  10. Would template areas make the layout easier to read?
Check grid container and direct childrenCheck columns, rows, gap, and implicit tracksCheck line numbers, spans, and areasUse DevTools grid overlay

20. Mini Practice

Create a responsive course card grid:

  • Each card should be at least 240px.
  • Cards should expand to fill available space.
  • The grid should use a 1rem gap.
  • It should work without a media query.

Possible answer:

.courses {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1rem;
}

Create a page shell:

  • Header spans full width.
  • Sidebar and main content sit side by side on desktop.
  • Footer spans full width.
  • Layout stacks on mobile.

Possible answer:

.page {
  display: grid;
  gap: 1rem;
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
}

.header {
  grid-area: header;
}

.sidebar {
  grid-area: sidebar;
}

.main {
  grid-area: main;
}

.footer {
  grid-area: footer;
}

@media (min-width: 800px) {
  .page {
    grid-template-columns: 260px minmax(0, 1fr);
    grid-template-areas:
      "header header"
      "sidebar main"
      "footer footer";
  }
}