CSS Grid Guide: Complete Grid Layout Tutorial (2026)

By Suvom Das March 27, 2026 22 min read

1. What Is CSS Grid?

CSS Grid Layout is a two-dimensional layout system designed specifically for creating complex web layouts. Unlike Flexbox, which handles one dimension at a time (either a row or a column), CSS Grid simultaneously controls both rows and columns, giving you precise control over the placement and sizing of elements in a two-dimensional space.

CSS Grid was introduced in major browsers in 2017 and has since become one of the most powerful tools in a web developer's arsenal. It fundamentally changed how we approach web layout, replacing decades of float-based and framework-dependent grid systems with a native CSS solution.

Key advantages of CSS Grid:

2. The Grid Container

A grid container is created by setting display: grid (or display: inline-grid) on an element. All direct children of the grid container automatically become grid items.

.container {
  display: grid;
}

Without any additional properties, a grid container stacks its items in a single column (one item per row), similar to normal block flow. The power of Grid comes from defining the column and row structure with template properties.

The difference between display: grid and display: inline-grid is how the container itself participates in the surrounding layout. grid creates a block-level container, while inline-grid creates an inline-level container. The internal grid behavior is identical.

Grid introduces several new concepts:

3. Grid Template Columns

The grid-template-columns property defines the number and sizes of columns in your grid. Each value defines one column track.

/* Three equal columns */
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

/* Mixed units */
.container {
  grid-template-columns: 200px 1fr 100px;
}

/* Using repeat() */
.container {
  grid-template-columns: repeat(4, 1fr);
}

/* Auto-sized columns */
.container {
  grid-template-columns: auto 1fr auto;
}

You can use any CSS length unit for column sizes: px, rem, em, %, fr, auto, min-content, max-content, or minmax(). The repeat() function is a shorthand for repeating track sizes.

Unit Behavior Example
frFraction of available space1fr 2fr (1:2 ratio)
pxFixed pixel width200px
autoSizes to fit contentauto
%Percentage of container33.33%
minmax()Size rangeminmax(200px, 1fr)

4. Grid Template Rows

The grid-template-rows property works exactly like grid-template-columns but defines the row tracks. It accepts the same units and functions.

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 80px 1fr 60px;
}

If you define more items than fit in the explicit rows, CSS Grid creates implicit rows to hold them. The size of implicit rows is controlled by the grid-auto-rows property.

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 100px 100px;     /* 2 explicit rows */
  grid-auto-rows: 80px;                /* Implicit rows are 80px */
}

For layouts where you want rows to size based on their content, use auto or min-content/max-content. For layouts where you want rows to fill available vertical space, use fr units.

5. The fr Unit

The fr (fraction) unit is unique to CSS Grid and is one of its most powerful features. It represents a fraction of the available space in the grid container after all fixed-size tracks have been calculated.

/* Equal columns: each gets 1/3 of space */
grid-template-columns: 1fr 1fr 1fr;

/* Unequal: second column is twice the first */
grid-template-columns: 1fr 2fr;

/* Mixed: fixed sidebar, flexible main */
grid-template-columns: 250px 1fr;

/* Fixed + flexible + fixed */
grid-template-columns: 200px 1fr 200px;

The calculation process works as follows: first, the browser calculates the sizes of all fixed tracks (px, auto, etc.) and subtracts them from the total container width. Then, the remaining space is divided among the fr tracks proportionally. If gap is specified, gap space is also subtracted before distributing fr space.

For example, if a 1000px container has grid-template-columns: 200px 1fr 2fr and a 20px gap, the calculation is: 1000px - 200px - 40px (two gaps) = 760px remaining, divided into 3 parts (1fr + 2fr). So 1fr = 253.3px and 2fr = 506.7px.

The fr unit is superior to percentages because it automatically accounts for gaps and fixed tracks. With percentages, you would need to manually calculate remaining space, and gaps could cause overflow.

6. Gap Property

The gap property (formerly grid-gap) sets the spacing between grid rows and columns. It is far superior to using margins because it only creates space between tracks, not at the container edges.

/* Same gap for rows and columns */
.container {
  gap: 20px;
}

/* Different row and column gaps */
.container {
  row-gap: 20px;
  column-gap: 10px;
}

/* Shorthand: row-gap column-gap */
.container {
  gap: 20px 10px;
}

The gap property works identically in both Grid and Flexbox layouts. It simplifies spacing considerably because you do not need to worry about margins on the first or last items, negative margins on the container, or pseudo-selector tricks to remove edge spacing.

7. Item Placement

One of Grid's most powerful features is explicit item placement. You can place items at specific positions using grid line numbers or spans.

/* Place item from column line 1 to line 3 */
.item {
  grid-column: 1 / 3;
}

/* Span 2 columns from the starting position */
.item {
  grid-column: span 2;
}

/* Place item in specific row and column */
.item {
  grid-column: 2 / 4;
  grid-row: 1 / 3;
}

/* Shorthand: grid-area: row-start / col-start / row-end / col-end */
.item {
  grid-area: 1 / 2 / 3 / 4;
}

Grid lines are numbered starting from 1 at the start edge. A 3-column grid has 4 vertical lines (1, 2, 3, 4). You can also use negative numbers to count from the end: -1 is the last line, -2 is second-to-last, etc. This is useful for spanning an item to the full width of the grid regardless of how many columns exist.

/* Span full width using negative line */
.full-width {
  grid-column: 1 / -1;
}

Items that are not explicitly placed are auto-placed by the grid auto-placement algorithm, which fills cells row by row (or column by column if grid-auto-flow: column is set).

8. Grid Areas

Grid areas provide a visual, declarative way to define your layout structure using ASCII-art-like syntax. This is one of Grid's most distinctive features and makes complex layouts remarkably readable.

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

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.aside   { grid-area: aside; }
.footer  { grid-area: footer; }

Each quoted string represents a row. Area names must form rectangles -- L-shapes or other non-rectangular areas are not allowed. Use a period (.) to denote an empty cell.

grid-template-areas:
  "header header header"
  "nav    main   ."
  "nav    footer footer";

Grid areas are especially useful for responsive design. You can redefine the entire layout structure in a media query by simply changing the grid-template-areas value, without touching any HTML.

/* Desktop: sidebar layout */
.container {
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}

/* Mobile: stacked layout */
@media (max-width: 768px) {
  .container {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "sidebar"
      "footer";
  }
}

9. Alignment Properties

CSS Grid provides granular control over alignment at both the container and item levels. There are two axes to consider: the inline axis (horizontal in LTR languages) and the block axis (vertical).

Container-Level Alignment

.container {
  /* Align items within their cells */
  justify-items: start | end | center | stretch;   /* Inline axis */
  align-items: start | end | center | stretch;     /* Block axis */

  /* Align the grid within the container */
  justify-content: start | end | center | stretch | space-between | space-around | space-evenly;
  align-content: start | end | center | stretch | space-between | space-around | space-evenly;
}

justify-items and align-items control how items are aligned within their grid cells. The default is stretch, which fills the entire cell. Setting these to start, center, or end causes items to take only their natural size.

justify-content and align-content control how the entire grid is positioned within the container when the grid is smaller than the container. These are only relevant when the grid tracks do not fill the entire container.

Item-Level Alignment

.item {
  justify-self: start | end | center | stretch;  /* Override justify-items */
  align-self: start | end | center | stretch;    /* Override align-items */
}

These properties allow individual items to override the container-level alignment. This is useful when most items should stretch to fill their cells but a specific item needs different alignment.

10. Auto-Fill and Auto-Fit

The auto-fill and auto-fit keywords work with repeat() to create responsive grids that automatically adjust the number of columns based on available space.

/* auto-fill: creates as many tracks as fit */
.container {
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

/* auto-fit: same, but collapses empty tracks */
.container {
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

The difference between auto-fill and auto-fit is subtle but important:

When combined with minmax(), these keywords create truly responsive grids without media queries. Items maintain a minimum width and wrap to new rows naturally as the viewport shrinks. This is one of the most popular CSS Grid patterns and eliminates the need for breakpoint-based column changes.

11. The minmax() Function

The minmax(min, max) function defines a size range for a grid track. The track will never be smaller than the minimum or larger than the maximum.

/* Columns at least 200px, max 1fr */
grid-template-columns: repeat(3, minmax(200px, 1fr));

/* Rows at least 100px, grow with content */
grid-template-rows: minmax(100px, auto);

/* Responsive pattern */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));

Common minmax() patterns:

The responsive grid pattern repeat(auto-fit, minmax(250px, 1fr)) is so common it has become a standard recommendation. It creates a grid where columns are at least 250px wide and automatically wrap to new rows as the container shrinks, all without a single media query.

12. Common Grid Layouts

Holy Grail Layout

The classic header, sidebar, main content, sidebar, footer layout.

.page {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header header"
    "left   main   right"
    "footer footer footer";
  min-height: 100vh;
}

Sidebar Layout

Fixed sidebar with flexible main content area.

.layout {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}
.header { grid-column: 1 / -1; }
.footer { grid-column: 1 / -1; }

Responsive Card Grid

Cards that automatically wrap to new rows as the viewport shrinks.

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

Dashboard Layout

A complex dashboard with widgets of different sizes.

.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto;
  gap: 1rem;
}
.widget-large  { grid-column: span 2; grid-row: span 2; }
.widget-wide   { grid-column: span 2; }
.widget-tall   { grid-row: span 2; }

Photo Gallery with Feature Image

A gallery where the first image is larger than the rest.

.gallery {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 200px);
  gap: 8px;
}
.gallery .featured {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

13. Best Practices

14. Using Our Grid Generator

Our CSS Grid Generator lets you build grid layouts visually. Add and configure columns and rows with individual size controls, choosing from fr, px, auto, or minmax units. Set column gap and row gap independently, and configure justify-items and align-items alignment. The live preview updates in real time, showing colored cells labeled with their row and column positions. Start from one of the built-in presets (Holy Grail, Sidebar, Photo Gallery, Dashboard, 3 Equal Columns, or Responsive Cards) and customize it to fit your needs. When you are satisfied, click Copy CSS to copy the production-ready CSS code to your clipboard.

The generator is ideal for learning CSS Grid interactively, prototyping layouts quickly, or generating CSS for production use. Everything runs client-side in your browser -- no data is sent to any server. Try it now and build your next grid layout in seconds.

Try the CSS Grid Generator →