CSS Grid Layout: Complete Guide with Examples and Generator

CSS Grid is the most powerful layout system available in CSS. It is a two-dimensional system, meaning it can handle both columns and rows simultaneously, unlike Flexbox which is fundamentally one-dimensional. Grid lets you define the structure of a page layout in CSS rather than in HTML, giving you precise control over how elements are sized, placed, and aligned across both axes.

Since gaining full cross-browser support in 2017, CSS Grid has gone from experimental to essential. As of 2026, over 97% of all browsers in use globally support CSS Grid, including every current version of Chrome, Firefox, Safari, and Edge. There is no practical reason to avoid Grid in any modern web project. This guide covers every major Grid concept with practical code examples you can use immediately, plus a visual tool to generate Grid CSS without writing it by hand.

1. What Is CSS Grid?

CSS Grid Layout is a CSS specification that introduces a two-dimensional grid-based layout system. You define a grid on a container element, specifying how many columns and rows it should have and how they should be sized. Child elements are then placed into that grid either automatically (in source order) or explicitly (using line numbers, span keywords, or named areas).

The key distinction between Grid and every layout method that came before it (floats, inline-block, tables, even Flexbox) is that Grid controls layout in two dimensions at the same time. You define both the column structure and the row structure on the container, and items flow into the resulting cells. Flexbox, by contrast, works in one dimension at a time. A flex row controls horizontal placement; a flex column controls vertical placement. To create a true two-dimensional layout with Flexbox, you end up nesting flex containers and relying on fixed widths or careful wrapping. Grid handles this natively.

When should you use Grid? Use it when you need to control both the horizontal and vertical placement of elements in a layout. Page scaffolding (header, sidebar, content, footer), card grids with strict row and column alignment, dashboard layouts with panels of different sizes, and form layouts with aligned labels and inputs are all ideal Grid use cases.

2. Grid Terminology

Before diving into properties, it helps to understand the six core concepts in Grid layout:

3. Basic Grid Setup

Every grid starts with a container. Apply display: grid and define the column and row structure using grid-template-columns and grid-template-rows:

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

This creates a grid with three columns (one fixed at 200px, two sharing the remaining space equally) and three rows (a 60px header row, a flexible content row, and a 40px footer row). Any direct children of .container are automatically placed into this grid in source order: the first child goes into row 1 / column 1, the second into row 1 / column 2, and so on.

If you only define columns and not rows, the grid creates rows implicitly as needed. The height of implicit rows is determined by the content inside them or by the grid-auto-rows property:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(100px, auto);
}

This is one of the most common Grid setups: three equal columns with rows that are at least 100px tall but grow to fit their content.

4. Sizing Tracks

Grid tracks can be sized using any CSS length unit, plus several Grid-specific functions:

Value Behavior Example
px Fixed width, does not flex grid-template-columns: 250px 250px
% Percentage of the container width grid-template-columns: 25% 75%
fr Fraction of remaining space grid-template-columns: 1fr 2fr
auto Sized by content, then takes remaining space grid-template-columns: auto 1fr
minmax() Sets a minimum and maximum size for the track grid-template-columns: minmax(200px, 1fr)
repeat() Repeats a track pattern N times grid-template-columns: repeat(4, 1fr)

The minmax() function is especially powerful. It lets you set a floor and ceiling for track size: minmax(150px, 1fr) means the track is never smaller than 150px but can grow to fill available space. This is the foundation of responsive grids without media queries.

The repeat() function avoids repetition. Instead of writing 1fr 1fr 1fr 1fr, you write repeat(4, 1fr). You can repeat complex patterns too: repeat(3, 1fr 2fr) produces six columns alternating between 1fr and 2fr.

5. The fr Unit Explained

The fr unit (fractional unit) is unique to CSS Grid. It represents a fraction of the available free space in the grid container after fixed-size tracks have been allocated.

Consider this example:

.container {
  display: grid;
  width: 900px;
  grid-template-columns: 200px 1fr 2fr;
}

The container is 900px wide. The first column takes a fixed 200px. The remaining 700px is divided into 3 fractional parts (1fr + 2fr = 3 parts): the second column gets 1/3 of 700px (approximately 233px) and the third column gets 2/3 of 700px (approximately 467px).

The fr unit also accounts for gaps. If you add gap: 20px to the example above, the browser first subtracts the gap space (2 gaps at 20px = 40px), then subtracts the fixed 200px column, and distributes the remaining 660px according to the fr ratios.

A common pattern is grid-template-columns: repeat(3, 1fr) for three equal-width columns. Because all tracks have the same fr value, the space is divided equally. This is simpler and more reliable than percentage-based approaches because fr accounts for gaps automatically, while percentages do not.

6. Grid Gaps

The gap property controls the space between grid tracks. It applies only between tracks, never at the outer edges of the grid:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;           /* Equal row and column gaps */
}

/* Or set them independently: */
.container {
  row-gap: 16px;
  column-gap: 24px;
}

The gap shorthand accepts one value (applied to both axes) or two values (gap: row-gap column-gap). You may encounter the older grid-gap, grid-row-gap, and grid-column-gap syntax in legacy codebases. These are deprecated aliases and still work, but the unprefixed gap, row-gap, and column-gap properties are the current standard and also work in Flexbox contexts.

Build Grid Layouts Visually

The SnapUtils CSS Grid Generator lets you define columns, rows, gaps, and named areas with a visual editor. Adjust the layout in real time and copy production-ready CSS with one click.

Open CSS Grid Generator

7. Placing Items on the Grid

By default, grid items fill cells in source order, left to right, top to bottom. But you can place any item at any position using line-based placement:

.item-a {
  grid-column-start: 1;
  grid-column-end: 3;    /* Spans from line 1 to line 3 (2 columns) */
  grid-row-start: 1;
  grid-row-end: 2;
}

/* Shorthand: */
.item-a {
  grid-column: 1 / 3;
  grid-row: 1 / 2;
}

The span keyword lets you specify how many tracks an item should span without knowing the exact line numbers:

.item-wide {
  grid-column: span 2;   /* Spans 2 columns from wherever it lands */
}

.item-tall {
  grid-row: span 3;      /* Spans 3 rows */
}

.item-featured {
  grid-column: 1 / span 2;  /* Starts at line 1, spans 2 columns */
  grid-row: 1 / span 2;     /* Starts at row 1, spans 2 rows */
}

You can also use negative line numbers. grid-column: 1 / -1 means "start at the first line and end at the last line," spanning the entire grid width regardless of how many columns exist. This is useful for full-width header or footer rows.

8. Grid Template Areas

Named grid areas are one of the most intuitive features of CSS Grid. You define a visual ASCII-art map of your layout directly in CSS, then assign elements to named regions:

.container {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    "header  header"
    "sidebar content"
    "footer  footer";
  gap: 0;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer  { grid-area: footer; }

Each quoted string represents one row. Each word in the string is a column. The same name repeated across cells means that area spans those cells. The resulting layout is immediately readable: a full-width header, a sidebar on the left with content on the right, and a full-width footer.

Use a period (.) to denote an empty cell:

grid-template-areas:
  "header header header"
  "sidebar . content"
  "footer footer footer";

Named areas also create implicit named lines. An area called header automatically generates lines named header-start and header-end on both axes. This lets you place other elements relative to named areas even if they are not assigned to an area themselves.

9. Alignment Properties

CSS Grid provides six alignment properties that control how items are positioned within their grid cells and how the grid itself is positioned within its container:

Item Alignment (on the container)

Content Alignment (on the container)

Self Alignment (on individual items)

The most useful shortcut: display: grid; place-items: center; centers a child both horizontally and vertically within the grid container. This single line replaces the classic "how to center a div" problem.

10. Common Layout Patterns

Holy Grail Layout

The classic header-sidebar-content-sidebar-footer layout that was notoriously difficult with floats is trivial with Grid:

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

.header  { grid-area: header; }
.left    { grid-area: left; }
.content { grid-area: content; }
.right   { grid-area: right; }
.footer  { grid-area: footer; }

Sidebar + Content

A fixed sidebar with a fluid content area:

.layout {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 24px;
  min-height: 100vh;
}

Responsive Card Grid

Cards that automatically wrap to fewer columns as the viewport narrows, without any media queries:

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 20px;
}

Dashboard Panel Layout

A dashboard with panels of different sizes, using span to make featured panels larger:

.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 200px;
  gap: 16px;
}

.panel-wide {
  grid-column: span 2;
}

.panel-tall {
  grid-row: span 2;
}

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

11. Grid vs Flexbox

Grid and Flexbox are complementary layout systems, not competitors. The choice depends on the nature of the layout problem:

Scenario Best Choice Why
Page-level scaffolding (header, sidebar, content, footer) Grid Two-dimensional structure defined on the container
Navigation bar items Flexbox Single row of items with flexible spacing
Card grid with strict row/column alignment Grid Items must align across both axes
Button group or toolbar Flexbox Items flow in one direction with variable sizes
Form layout with aligned labels and inputs Grid Label and input columns must align across rows
Centering a single element Either Grid: place-items: center. Flex: justify-content: center; align-items: center

In practice, most production layouts use both. A page might use Grid for the overall structure (header, sidebar, content areas) while each section internally uses Flexbox for its component-level layout (a nav bar inside the header, a list of cards inside the content area). Grid items can be Flex containers, and Flex items can be Grid containers. There is no conflict.

Rule of thumb: If you are laying out items in one direction (a row of buttons, a vertical stack of cards), use Flexbox. If you are laying out items in two directions simultaneously (a page structure, a data table, a dashboard), use Grid.

12. Responsive Grids

auto-fill vs auto-fit

The repeat() function accepts two special keywords instead of a fixed count: auto-fill and auto-fit. Both create as many tracks as will fit in the container, but they differ when there are fewer items than tracks.

/* auto-fill: keeps empty tracks, maintaining the grid structure */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

/* auto-fit: collapses empty tracks, letting items stretch to fill */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

With auto-fill, if your container can fit 4 columns but you only have 2 items, the remaining 2 columns still exist as empty space. With auto-fit, those empty columns collapse to zero width, and your 2 items stretch to fill the full container width.

For card grids where you want consistent column sizes regardless of how many cards are displayed, auto-fill is usually the better choice. For layouts where items should always fill the container (like a set of navigation links), auto-fit works better.

Media Queries with Grid

While auto-fill and minmax() handle many responsive scenarios without media queries, you sometimes need explicit breakpoints for major layout changes, such as collapsing a sidebar from a side-by-side layout to a stacked layout on mobile:

.layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

@media (min-width: 768px) {
  .layout {
    grid-template-columns: 260px 1fr;
    grid-template-areas:
      "sidebar content";
  }
}

This gives you a single-column stacked layout on small screens and a sidebar layout on wider screens. The combination of intrinsic sizing with minmax() for card-level grids and explicit media queries for structural layout changes covers virtually every responsive scenario you will encounter.

Generate Grid CSS Visually

Stop writing grid-template-columns from scratch. The SnapUtils CSS Grid Generator lets you visually define your grid structure, adjust columns, rows, and gaps in real time, and export clean CSS code ready for production.

Try the Grid Generator

13. Frequently Asked Questions

CSS Grid is a two-dimensional layout system that controls both rows and columns simultaneously. Flexbox is one-dimensional — it handles either a row or a column at a time. Use Grid when you need to control placement in both axes (page layouts, dashboards, card grids with strict alignment). Use Flexbox when you need items to flow in a single direction (navbars, button groups, centering a single element). They are complementary: Grid items can be Flex containers and vice versa.

The fr unit stands for "fraction of available space." It distributes remaining space in the grid container after fixed-size tracks (px, rem, etc.) and gaps have been allocated. For example, grid-template-columns: 200px 1fr 2fr creates three columns: the first is always 200px, and the remaining space is split into 3 equal parts — 1 part to the second column and 2 parts to the third. The fr unit is preferred over percentages because it automatically accounts for gap space.

Use the repeat() function with auto-fill or auto-fit and minmax(). For example: grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)). This creates as many columns as will fit at a minimum of 250px each, automatically wrapping to fewer columns as the viewport shrinks. The grid adapts entirely based on available space without any media queries.

Both auto-fill and auto-fit create as many tracks as will fit in the container. The difference appears when there are fewer items than tracks: auto-fill keeps the empty tracks, preserving their space in the layout. auto-fit collapses empty tracks to zero width, allowing existing items to stretch and fill the remaining space. For most card grids, auto-fill is the better default because the column sizes remain consistent regardless of item count.

Yes. CSS Grid has over 97% global browser support as of 2026, including all modern versions of Chrome, Firefox, Safari, Edge, and mobile browsers on both iOS and Android. The only browsers that lack support are Internet Explorer (end-of-life since June 2022) and very old Android WebView versions. CSS Grid is production-safe for virtually all web projects today without any polyfill or fallback.

The simplest method is display: grid; place-items: center; on the container. This shorthand sets both align-items: center and justify-items: center, centering all child items both vertically and horizontally within their grid cells. For centering all content in the viewport, apply this to a full-height container: display: grid; place-items: center; min-height: 100vh;. This two-line pattern is the modern solution to the classic "how to center a div" question.

Related Articles