CSS Grid

Two-dimensional layout with display: grid — template columns and rows, gap, grid-area, and a dashboard example.

Grid vs flexbox

Flexbox is one-dimensional — it lays items out along a single axis (a row, or a column). CSS Grid (display: grid) is two-dimensional — it lets you define rows and columns simultaneously and place items anywhere within that structure. Grid is the right tool whenever a layout needs to align content both horizontally and vertically at once, like a full page layout or a dashboard.

Css
.container {
    display: grid;
}

Defining the grid

Css
.grid {
    display: grid;
    grid-template-columns: 200px 1fr 1fr;   /* 3 columns: fixed, flexible, flexible */
    grid-template-rows: 80px auto 60px;      /* 3 rows: header, content, footer */
    gap: 1rem;
}
  • grid-template-columns / grid-template-rows — define the size of each column/row, space-separated.
  • fr ("fraction") — a unit unique to grid: divides remaining space proportionally. 1fr 2fr splits leftover space into thirds, giving the second column twice the first's share.
  • gap — spacing between grid cells (same idea as flexbox's gap).

The repeat() function avoids repetitive declarations:

Css
.grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr); /* 4 equal columns */
    gap: 1rem;
}

Auto-fit / auto-fill responsive grids

A very common pattern — a grid that automatically adds or removes columns based on available width, with zero media queries:

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

Each column is at least 220px, and as many columns as will fit are created automatically — resize the viewport and the number of columns adjusts on its own.

Placing items: grid-area and line-based placement

By default, items fill the grid left-to-right, top-to-bottom, one per cell. You can explicitly place an item using grid line numbers or named areas.

Css
.item {
    grid-column: 1 / 3;   /* start at column line 1, end at column line 3 (spans 2 columns) */
    grid-row: 2 / 4;      /* start at row line 2, end at row line 4 */
}

Named template areas are often more readable for page-level layouts:

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

.sidebar { grid-area: sidebar; }
.header  { grid-area: header; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }
HTML
<div class="layout">
    <aside class="sidebar">Sidebar</aside>
    <header class="header">Header</header>
    <main class="main">Main content</main>
    <footer class="footer">Footer</footer>
</div>

The ASCII-art-like grid-template-areas value is one of grid's most readable features — the CSS literally looks like a diagram of the layout.

Practical example: a dashboard layout

HTML
<div class="dashboard">
    <header class="dashboard-header">Dashboard</header>
    <nav class="dashboard-nav">Nav</nav>
    <main class="dashboard-main">Main content</main>
    <aside class="dashboard-aside">Stats</aside>
    <footer class="dashboard-footer">Footer</footer>
</div>
Css
.dashboard {
    display: grid;
    grid-template-columns: 220px 1fr 280px;
    grid-template-rows: 64px 1fr 48px;
    grid-template-areas:
        "nav    header header"
        "nav    main   aside"
        "nav    footer footer";
    gap: 1rem;
    min-height: 100vh;
}

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

/* collapse to a single column on small screens */
@media (max-width: 768px) {
    .dashboard {
        grid-template-columns: 1fr;
        grid-template-areas:
            "header"
            "nav"
            "main"
            "aside"
            "footer";
    }
}

This is the classic "holy grail" layout (header, footer, nav, main, sidebar) — something that historically required floats and negative margins, and now takes about a dozen lines of grid CSS, including the responsive collapse.

Grid vs flexbox — when to use which

Flexbox Grid
Dimensions One (row or column) Two (rows and columns)
Best for Navbars, button groups, aligning items along one line Full page layouts, dashboards, image galleries
Sizing driven by Content The explicit grid definition
Item placement Follows source order (mostly) Can be placed anywhere in the grid explicitly

In practice, most real UIs use both: grid for the overall page structure, flexbox for aligning content within an individual grid cell (like centering a button inside a card).

Common mistakes

  • Reaching for grid to align a single row of items (like a navbar) — flexbox is simpler and more idiomatic for one-dimensional alignment.
  • Forgetting that grid line numbers start at 1, not 0, and that grid-column: 1 / 3 means "from line 1 to line 3" (spanning 2 tracks), not "columns 1 through 3."
  • Not testing auto-fit/auto-fill grids at very narrow widths — without a sensible minmax() lower bound, columns can become uncomfortably narrow before wrapping.
  • Mixing up grid-template-areas names with typos — a single mismatched name between the template and an item's grid-area silently drops that item into the default flow instead of erroring.