Grid Placement & Areas

CSS · Lesson 28 of 55 7 min read Updated

In CSS Grid Basics the browser placed every item for you, one after another. That automatic placement is fine for a gallery, but a page layout or a dashboard needs more control: this box across two columns, that one in the bottom-right corner, the footer along the full width.

This lesson shows two ways to place items exactly: by grid line numbers and by named areas. You will also see how to overlap items and why the HTML order still matters.

Grid lines are numbered

Every grid has numbered lines between and around its tracks. A grid with three columns has four vertical lines: line 1 on the left edge, then lines 2 and 3 between the columns, and line 4 on the right edge. Rows work the same way from top to bottom.

Lines are also numbered backwards from the end with negative numbers. Line -1 is always the last line of the explicit grid, so 1 / -1 means "from the first line to the last", whatever the number of columns.

Browser DevTools can draw these numbers for you. In Chrome, Edge or Firefox, open DevTools, select a grid container and click the small "grid" badge next to it in the Elements panel.

Placing items with line numbers

grid-column and grid-row take a start line and an end line separated by a slash. Instead of an end line, you can write span and a number of tracks.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Dashboard placement</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 16px; }
    .dashboard {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-auto-rows: 90px;
      gap: 10px;
    }
    .dashboard div {
      padding: 10px;
      border-radius: 8px;
      background: #e0e7ff;
    }
    .sales    { grid-column: 1 / 3; grid-row: 1 / 3; background: #c7d2fe; }
    .orders   { grid-column: 3 / -1; }
    .visitors { grid-column: span 2; }
    .notes    { grid-column: 1 / -1; }
  </style>
</head>
<body>
  <div class="dashboard">
    <div class="sales">Sales this week: ₹48,200</div>
    <div class="orders">Orders: 126</div>
    <div class="visitors">Visitors: 2,310</div>
    <div class="notes">Note: Diwali offer ends on Friday</div>
  </div>
</body>
</html>

Here is how each box is placed:

  • Sales runs from column line 1 to line 3 and from row line 1 to line 3, so it covers a 2 by 2 block.
  • Orders runs from line 3 to the last line, filling the top-right.
  • Visitors only says span 2. The browser finds the first free space that is two columns wide, which is next to Sales in row 2.
  • Notes runs from the first to the last line, so it takes the full width of row 3.

The grid-area property can set all four lines at once in the order row-start, column-start, row-end, column-end. grid-area: 1 / 1 / 3 / 3 would place Sales exactly as above. It is short but harder to read, so many developers prefer grid-column and grid-row.

Naming lines

Numbers are hard to remember in a big layout. You can give lines names by writing them in square brackets inside the track list. A popular use is an article layout where text stays in a readable centre column but some items stretch to the edges.

CSS
.article {
  display: grid;
  grid-template-columns:
    [full-start] 1fr
    [content-start] min(65ch, 100% - 2rem) [content-end]
    1fr [full-end];
}

.article > * {
  grid-column: content;    /* normal text stays in the middle */
}

.article > .wide-photo {
  grid-column: full;       /* photos run edge to edge */
}

When lines are named something-start and something-end, Grid lets you use just something as a shortcut for the whole span between them. That is why grid-column: content works here. The centre column is never wider than 65 characters, which is comfortable to read, and on a phone it shrinks to the screen width minus 2rem.

Drawing a layout with grid-template-areas

grid-template-areas lets you draw the layout as a picture made of words. Each string in quotes is one row, and each word is one cell. Repeat a word to make an area cover several cells. Then give each item a matching grid-area name.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Page areas</title>
  <style>
    body { margin: 0; font-family: system-ui, sans-serif; }
    .page {
      display: grid;
      gap: 10px;
      padding: 10px;
      grid-template-areas:
        "header"
        "main"
        "sidebar"
        "footer";
    }
    .page > * { padding: 16px; border-radius: 8px; background: #f1f5f9; }
    header { grid-area: header; background: #1e3a8a; color: white; }
    main   { grid-area: main; min-height: 200px; }
    aside  { grid-area: sidebar; background: #fef9c3; }
    footer { grid-area: footer; background: #e2e8f0; }

    @media (min-width: 40rem) {
      .page {
        grid-template-columns: 1fr 220px;
        grid-template-areas:
          "header  header"
          "main    sidebar"
          "footer  footer";
      }
    }
  </style>
</head>
<body>
  <div class="page">
    <header>Lucknow Cricket Academy</header>
    <main>Match reports and coaching news go here.</main>
    <aside>Upcoming fixtures</aside>
    <footer>Contact the academy office</footer>
  </div>
</body>
</html>

On a narrow screen everything stacks in one column. From 40rem wide, the media query draws a new picture: the header and footer span both columns and the sidebar sits next to the main content. Only the grid container changes; the items keep their area names. You will learn more about media queries in Responsive Design & Media Queries.

A few rules for the picture:

  • Every string must have the same number of words (cells).
  • Each area must be a rectangle. An L-shaped area is invalid, and the whole declaration is ignored.
  • Use a full stop . for an empty cell, for example "header .".

Overlapping items

Two items can be placed in the same cell. This is a clean way to put text on top of an image without position: absolute.

CSS
.hero {
  display: grid;
  grid-template-areas: "stack";
}

.hero > * {
  grid-area: stack;     /* image and caption share one cell */
}

.hero .caption {
  align-self: end;      /* caption sits at the bottom of the image */
  z-index: 1;
  padding: 1rem;
  background: rgb(0 0 0 / 0.6);
  color: white;
}

When items overlap, later items in the HTML are drawn on top. Grid items also accept z-index without needing position, so you can control the stacking order directly.

Common mistakes

  • Counting columns instead of lines. A three-column grid ends at line 4, not line 3. Use -1 when you mean "the last line".
  • Uneven area strings. If one row has three words and another has two, the browser ignores the whole grid-template-areas declaration and the items land in unexpected places.
  • Area names that do not match. grid-area: side will not land in an area called sidebar. Check the spelling in both places.
  • Writing quotes around grid-area values. Use grid-area: header, not grid-area: "header". Quotes belong only in grid-template-areas.

Key points

  • Grid lines are numbered from 1, and negative numbers count from the end, so 1 / -1 spans the full explicit grid.
  • grid-column and grid-row take a start and an end line, or a span count.
  • Named lines such as [content-start] and [content-end] let you write grid-column: content.
  • grid-template-areas draws the layout as rows of words; items join an area with grid-area.
  • Change the template inside a media query to rearrange the whole layout without touching the items.
  • Items can overlap in the same cell; the HTML order should still be the reading order.

Exercise

Create a layout for a school notice board with four parts: a title bar, a "Notices" area, an "Events" area and a "Contact" strip. On small screens, stack them in that order. From 48rem wide, use two columns: the title bar and contact strip across the full width, with Notices and Events side by side. Use grid-template-areas.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Notice board</title>
  <style>
    .board {
      display: grid;
      gap: 12px;
      grid-template-areas: "title" "notices" "events" "contact";
    }
    .title   { grid-area: title; }
    .notices { grid-area: notices; }
    .events  { grid-area: events; }
    .contact { grid-area: contact; }
    @media (min-width: 48rem) {
      .board {
        grid-template-columns: 1fr 1fr;
        grid-template-areas:
          "title   title"
          "notices events"
          "contact contact";
      }
    }
  </style>
</head>
<body>
  <div class="board">
    <h1 class="title">Kochi Public School</h1>
    <section class="notices">Notices</section>
    <section class="events">Events</section>
    <p class="contact">Office: 9 am to 4 pm</p>
  </div>
</body>
</html>

The items only declare which area they belong to. The media query swaps in a two-column picture, and the title and contact strip repeat their names to span both columns.

Quick Quiz

1. In a grid with four columns, what does grid-column: 1 / -1 do?

2. What does grid-column: span 3 mean?

3. Which grid-template-areas value is invalid?

4. Why should you avoid using Grid to show content in a very different order from the HTML?

Learn CSS with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call