Grid Alignment

▶ Try It Yourself

CSS Grid has a rich alignment system with six properties that control how the entire grid sits within its container and how individual items sit within their cells. While Flexbox alignment operates along a single axis, Grid alignment works independently on both the row and column axes simultaneously. In this lesson you will master all six alignment properties and understand the key differences between aligning the grid tracks versus aligning individual items.

The Six Grid Alignment Properties

Property Applies To Controls
justify-content Container Positions the entire grid along the inline (row) axis — when grid is smaller than container
align-content Container Positions the entire grid along the block (column) axis — when grid is smaller than container
justify-items Container Default inline alignment of all items within their cells
align-items Container Default block alignment of all items within their cells
justify-self Item Override inline alignment for one specific item
align-self Item Override block alignment for one specific item

Common Values for All Six Properties

Value Meaning Items/Tracks Behaviour
start Align to start edge of the axis Items: left/top of cell. Tracks: left/top of container
end Align to end edge of the axis Items: right/bottom of cell. Tracks: right/bottom of container
center Centre along the axis Items centred in cell. Tracks grouped in centre
stretch Default for items — fills the cell Items fill entire cell width/height
space-between Tracks/content only — equal gaps between First and last tracks at container edges
space-evenly Tracks/content only — equal gaps everywhere Equal space including outer edges

place-items and place-content Shorthand

Shorthand Expands To Example
place-items: A B align-items: A; justify-items: B place-items: center start
place-items: A align-items: A; justify-items: A place-items: center — both axes
place-content: A B align-content: A; justify-content: B place-content: center space-between
place-self: A B align-self: A; justify-self: B place-self: end center
Note: justify-items / align-items control how items are aligned inside their cells. justify-content / align-content control how the entire grid of tracks is positioned inside the container — these only have a visible effect when the sum of tracks is smaller than the container. With 1fr tracks, content always fills the container, so justify-content does nothing.
Tip: The quickest way to perfectly centre an item inside its grid cell on both axes is place-self: center on the item, or place-items: center on the container to centre all items. This is cleaner than the classic display: flex; align-items: center; justify-content: center wrapper trick for grid scenarios.
Warning: Setting justify-items or align-items to anything other than stretch means items no longer fill their cell. An item that was 100% of its cell width with stretch will shrink to fit-content size with center or start. This is often surprising — use justify-self or align-self on individual items when you only want to change alignment for specific cells.

Basic Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Grid Alignment</title>
  <style>
    *, *::before, *::after { box-sizing: border-box; }
    body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; }
    .label { font-size: 0.75rem; font-weight: 700; text-transform: uppercase;
             letter-spacing: 0.06em; color: #64748b; margin-bottom: 8px; }

    .grid-wrap {
      background: #e0e7ff;
      border-radius: 10px;
      padding: 8px;
      margin-bottom: 24px;
      height: 200px;          /* taller than tracks to show content alignment */
    }

    .demo-grid {
      display: grid;
      grid-template-columns: repeat(3, 120px);  /* fixed — leaves horizontal space */
      grid-auto-rows: 80px;
      gap: 8px;
      height: 100%;
    }

    .cell {
      background: #4f46e5;
      border-radius: 6px;
      color: white;
      font-size: 0.75rem;
      font-weight: 700;
      display: flex; align-items: center; justify-content: center;
    }

    /* justify-content: tracks inside container (horizontal) */
    .jc-center    { justify-content: center; }
    .jc-end       { justify-content: end; }
    .jc-sb        { justify-content: space-between; }

    /* align-content: tracks inside container (vertical) */
    .ac-center    { align-content: center; }
    .ac-end       { align-content: end; }

    /* place-content shorthand */
    .pc-center    { place-content: center; }

    /* justify-items: items inside their cells */
    .ji-center    { justify-items: center; }
    .ji-start     { justify-items: start; }

    /* align-items: items inside cells vertically */
    .ai-end       { align-items: end; }

    /* Individual self overrides */
    .self-demo { place-content: center; place-items: start; }
    .self-center { place-self: center; background: #10b981; }
    .self-end    { align-self: end; justify-self: end; background: #f59e0b; }
  </style>
</head>
<body>

  <div class="label">justify-content: center — tracks centred horizontally</div>
  <div class="grid-wrap">
    <div class="demo-grid jc-center ac-center">
      <div class="cell">A</div><div class="cell">B</div><div class="cell">C</div>
    </div>
  </div>

  <div class="label">place-content: center — entire grid centred both axes</div>
  <div class="grid-wrap">
    <div class="demo-grid pc-center">
      <div class="cell">A</div><div class="cell">B</div><div class="cell">C</div>
    </div>
  </div>

  <div class="label">justify-items: center — items centred inside their cells</div>
  <div class="grid-wrap">
    <div class="demo-grid jc-center ac-center ji-center ai-end" style="grid-template-columns:repeat(3,1fr)">
      <div class="cell" style="width:80px">A</div>
      <div class="cell" style="width:80px">B</div>
      <div class="cell" style="width:80px">C</div>
    </div>
  </div>

  <div class="label">Individual place-self overrides — green: center, yellow: end-end</div>
  <div class="grid-wrap">
    <div class="demo-grid self-demo" style="grid-template-columns:repeat(3,1fr);place-items:start">
      <div class="cell" style="width:70px">start</div>
      <div class="cell self-center" style="width:70px">center</div>
      <div class="cell self-end" style="width:70px">end</div>
    </div>
  </div>

</body>
</html>

How It Works

Step 1 — Fixed Tracks Leave Space for justify-content

Three 120px fixed columns total 360px. In an 800px container, 440px of horizontal space is left over. justify-content: center distributes this surplus equally on both sides of the track group, centering the entire grid horizontally within the container.

Step 2 — place-content: center Centres Both Axes

place-content: center is shorthand for align-content: center; justify-content: center. With the container taller than the track heights (container: 184px inner, tracks: 2×80px + gap = 168px), the vertical surplus is also centred. All four sides have equal space.

Step 3 — justify-items Shrinks Items to Fit-Content

With fluid 1fr columns, each cell is ~260px wide. Setting justify-items: center makes the 80px-wide items center within their 260px cells — they no longer stretch to fill the full cell width. The background of each item covers only 80px, not the full cell.

Step 4 — place-self Overrides Container Alignment

With the container set to place-items: start (all items top-left), the green item uses place-self: center to centre itself within its cell, and the yellow item uses align-self: end; justify-self: end to pin itself to the bottom-right of its cell.

Step 5 — stretch Is the Productive Default

The default align-items: stretch; justify-items: stretch makes all items fill their grid cells completely — row-height and column-width determined by the track definitions. This is why grid-based card layouts look clean without explicitly sizing every card.

Real-World Example: Product Grid with Centred Thumbnails

/* product-alignment.css */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; padding: 40px 24px; }

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
  /* align-items: stretch by default — all cards same height */
}

.product-card {
  background: white;
  border-radius: 16px;
  border: 1px solid #e2e8f0;
  overflow: hidden;
  display: grid;
  grid-template-rows: 200px auto 1fr auto;  /* img, tag, text, btn */
}

/* Image cell: item centred within 200px row */
.product-img-cell {
  background: #f1f5f9;
  display: grid;
  place-items: center;   /* centre the img within the cell */
  overflow: hidden;
}
.product-img-cell img {
  width: 140px;
  height: 140px;
  object-fit: contain;
  transition: transform 0.3s;
}
.product-card:hover .product-img-cell img { transform: scale(1.05); }

.product-tag {
  padding: 12px 16px 0;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #4f46e5;
}

.product-info { padding: 8px 16px 0; }
.product-name { font-size: 0.95rem; font-weight: 700; color: #0f172a; margin-bottom: 4px; }
.product-desc { font-size: 0.8rem; color: #64748b; line-height: 1.5; }

.product-footer {
  padding: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid #f1f5f9;
  margin-top: 12px;
  align-self: end;   /* pin footer to bottom of card regardless of content */
}
.product-price { font-size: 1.1rem; font-weight: 800; color: #0f172a; }
.add-btn {
  background: #4f46e5; color: white;
  border: none; border-radius: 8px;
  padding: 8px 14px; font-size: 0.8rem; font-weight: 600;
  cursor: pointer;
}

Common Mistakes

Mistake 1 — Expecting justify-content to work with fr tracks

❌ Wrong — fr tracks always fill all available space; no surplus for justify-content:

.grid { display: grid; grid-template-columns: repeat(3, 1fr); justify-content: center; }
/* 1fr tracks fill 100% of container — justify-content has no free space to act on */

✅ Correct — use fixed track sizes to leave space for justify-content:

.grid { display: grid; grid-template-columns: repeat(3, 200px); justify-content: center; }

Mistake 2 — Confusing justify-items with justify-content

❌ Wrong — using justify-content to centre items inside their cells:

.grid { display: grid; grid-template-columns: repeat(3, 1fr); justify-content: center; }
/* Does not centre items inside cells — moves the track group */

✅ Correct — use justify-items to centre items within their cells:

.grid { display: grid; grid-template-columns: repeat(3, 1fr); justify-items: center; }

Mistake 3 — Forgetting align-content requires height on the container

❌ Wrong — container has no explicit height; tracks fill it; align-content does nothing:

.grid { display: grid; align-content: center; } /* container height = sum of tracks */

✅ Correct — give the container a height larger than the total track height:

.grid { display: grid; height: 500px; align-content: center; }

▶ Try It Yourself

Quick Reference

Property Axis Aligns Shorthand
justify-content Inline (row) Whole grid in container place-content
align-content Block (col) Whole grid in container place-content
justify-items Inline (row) All items in their cells place-items
align-items Block (col) All items in their cells place-items
justify-self Inline (row) One item in its cell place-self
align-self Block (col) One item in its cell place-self

🧠 Test Yourself

You want to centre a grid item within its cell on both axes without affecting other items. Which property do you use on the item?





▶ Try It Yourself