CSSGrid Item Placement

Grid placement & spanning

Grid items can be placed explicitly in specific cells or allowed to auto-place. The grid-column and grid-row properties specify which columns and rows an item spans. Items can span multiple cells, creating complex layouts. Understanding placement is key to harnessing grid's power.

Auto-placement

By default, grid items automatically fill cells in row order. You can control this with grid-auto-flow.

CSS
<!-- Items auto-place in reading order -->
<div class="grid">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* 3 columns, rows auto-create -->
}

<!-- Auto-placement flow: row (default) -->
[1] [2] [3]
[4] [5] [6]

.grid {
  grid-auto-flow: column;  /* fill columns first -->
}

<!-- Auto-placement flow: column -->
[1] [4]
[2] [5]
[3] [6]

.grid {
  grid-auto-flow: dense;  /* fill gaps with smaller items -->
}

<!-- Tries to prevent gaps for better space usage -->
grid-column and grid-row

Property

Syntax

Example

Result

grid-column

start / end

1 / 3

Span columns 1-2

grid-row

start / end

1 / 3

Span rows 1-2

grid-column

start / span

2 / span 2

Span 2 columns from 2

grid-column

start / -1

1 / -1

Span to grid end

CSS
<!-- Three-column grid -->
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

<!-- Position item in specific cell -->
.item {
  grid-column: 2;      /* place in column 2 -->
  grid-row: 1;         /* place in row 1 -->
}

<!-- Span multiple cells -->
.item {
  grid-column: 1 / 3;  /* span columns 1-2 -->
  grid-row: 1 / 3;     /* span rows 1-2 -->
}

<!-- Span using span keyword -->
.item {
  grid-column: 1 / span 2;  /* start column 1, span 2 columns -->
  grid-row: 1 / span 3;     /* start row 1, span 3 rows -->
}

<!-- Span to the end -->
.item {
  grid-column: 1 / -1;  /* span from column 1 to grid end -->
  grid-row: 1 / -1;     /* span from row 1 to grid end -->
}

<!-- Only column (row auto-places) -->
.item {
  grid-column: 2;
  /* grid-row: auto (automatic) */
}
Grid areas with named cells

Named grid areas provide a semantic way to define layout regions and place items.

CSS
<!-- Define layout with named areas -->
<div class="app">
  <header>Header</header>
  <nav>Navigation</nav>
  <main>Main Content</main>
  <aside>Sidebar</aside>
  <footer>Footer</footer>
</div>

.app {
  display: grid;
  grid-template-columns: 200px 1fr 250px;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    "header header header"
    "nav main sidebar"
    "footer footer footer";
  gap: 20px;
}

header {
  grid-area: header;
}

nav {
  grid-area: nav;
}

main {
  grid-area: main;
}

aside {
  grid-area: sidebar;
}

footer {
  grid-area: footer;
}

<!-- Result -->
[════════ Header ════════]
[Nav]    [Main]    [Sidebar]
[════════ Footer ════════]

<!-- Responsive: change areas on mobile -->
@media (max-width: 768px) {
  .app {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto auto auto;
    grid-template-areas:
      "header"
      "nav"
      "main"
      "sidebar"
      "footer";
  }
}

<!-- Result on mobile -->
[Header]
[Nav]
[Main]
[Sidebar]
[Footer]
Practical spanning patterns

CSS
<!-- Magazine-style layout with featured article -->
<div class="magazine">
  <article class="featured">Featured</article>
  <article>Article 1</article>
  <article>Article 2</article>
  <article>Article 3</article>
  <article>Article 4</article>
</div>

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

.featured {
  grid-column: 1 / 3;  /* span 2 columns -->
  grid-row: 1 / 3;     /* span 2 rows -->
}

<!-- Result -->
[═════Featured═════] [Article 1]
[═════Featured═════] [Article 2]
[Article 3] [Article 4]

<!-- Dashboard with larger widget -->
<div class="dashboard">
  <div class="widget main">Main Widget</div>
  <div class="widget">Widget 2</div>
  <div class="widget">Widget 3</div>
  <div class="widget">Widget 4</div>
</div>

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

.widget {
  background: white;
  border: 1px solid #eeeeee;
  padding: 20px;
  border-radius: 8px;
}

.widget.main {
  grid-column: span 6;  /* take 6 columns -->
}

.widget {
  grid-column: span 3;  /* take 3 columns -->
}

<!-- Result: main widget is 2×2, others are 1×1 -->
Dense packing to avoid gaps

CSS
<!-- Without dense: gaps created -->
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-flow: row;  /* row by row -->
}

.item:nth-child(1) {
  grid-column: span 2;
}

<!-- [═══Item 1═══] [───]
     [Item 2] [Item 3] [Item 4]
     [Item 5] [Item 6] -->

<!-- With dense: fills gaps -->
.grid {
  grid-auto-flow: dense;  /* rearrange to fill gaps -->
}

<!-- [═══Item 1═══] [Item 5]
     [Item 2] [Item 3] [Item 4]
     [Item 6] -->

<!-- Item 5 moves up to fill gap -->
Negative positioning with -1

Use -1 to reference the grid end, useful for spanning to the end without knowing total columns.

CSS
<!-- Span from column 1 to grid end -->
.full-width {
  grid-column: 1 / -1;  /* automatically spans entire width -->
}

<!-- Works regardless of how many columns exist -->

<!-- Span from row 2 to grid end -->
.tall {
  grid-row: 2 / -1;
}

<!-- Practical: auto-sizing footer -->
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto 1fr auto;
}

footer {
  grid-column: 1 / -1;  /* always spans full width -->
  grid-row: 3;
}
Note
Grid placement can be powerful but also complex. Start with auto-placement, then use explicit positioning only when needed. Named grid areas make layouts more readable.
Dense can cause accessibility issues
Using `grid-auto-flow: dense` can reorder items visually, which may confuse keyboard and screen reader users. Use it carefully and test with accessibility tools.
Next
Auto-sizing and responsive grids: [grid auto & minmax](/css/grid-auto-sizing).