CSS · Lesson 9

Grid: Container

Building rows and columns

Flexbox lines things up in one direction. Grid works in two at once: rows and columns. It's the easiest way to build galleries, card grids and whole page layouts.

What you'll learn

  • How display: grid places the children of a box in rows and columns.
  • How to set columns and rows with px, fr and repeat(), and add gaps.
  • How to plan a whole page with named areas, line items up inside their cells, and move the whole grid.

Let's draw a grid

You add display: grid; to the parent, called the grid container. Then you describe its columns and rows, and its children, the grid items, fill the cells one by one, from left to right and top to bottom.

Think of a calendar page. It has seven columns, one for each day of the week, all the same width. The dates fill the boxes in order, and a new row starts every week. There is a small gap between every box. A CSS grid works the same way: you choose the columns, and the items fill them in order.

The month starts on a Thursday, so the first four boxes stay empty, and the dates fill the rest of the boxes in order. One line of CSS sets all seven columns.

A closer look

Columns and the fr unit

grid-template-columns lists one size for each column. 90px 90px 90px makes three fixed columns. fr means "a fraction of the free space": 1fr 1fr 1fr makes three equal columns that fill the container, and 1fr 2fr makes the second column twice as wide as the first. repeat(3, 1fr) is a short way to write 1fr 1fr 1fr.

Rows and gaps

grid-template-rows works the same way for rows. Rows you don't list are added as needed, and they fit their content. gap adds space between all rows and columns, just like in flexbox.

Planning a page with grid-template-areas

grid-template-areas lets you draw the page with words. Each string is one row, and each word is one column. Repeat a word to make an area wider or taller. Then put each item in its area with grid-area (more about it in CSS Lesson 10).

Lining items up inside their cells

By default, every item stretches to fill its cell. justify-items moves all items left and right inside their cells, and align-items moves them up and down. Here, both use the same value.

Moving the whole grid: justify-content and align-content

Sometimes the columns are narrower than the container, for example three 40px columns in a wide box. Then there is leftover space, and justify-content decides where the whole grid goes: left, center, right, or spread out between the columns. align-content does the same up and down, when the container is taller than its rows.

Let's build it

Let's place six Front Page Bytes category cards in a grid, then plan a whole page. Each code box opens on the CSS tab with the new lines highlighted. Click HTML to see the page being styled.

Step 1: Turn on grid with three columns

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: 90px 90px 90px;}
What you see

display: grid; turns .grid into a grid container, and grid-template-columns makes three columns, each 90 pixels wide. The six cards fill them in order: three per row.

Step 2: Let the columns fill the space: fr

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: 1fr 1fr 1fr;}
What you see

1fr 1fr 1fr shares all the free space into three equal parts, so the grid now fills the whole width of the page.

Step 3: Write it shorter: repeat()

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: repeat(3, 1fr);}
What you see

repeat(3, 1fr) means "three columns of 1fr". The result is the same, and it's easy to change to 4 or 5 columns later.

Step 4: Add gaps

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: repeat(3, 1fr);  gap: 12px;}
What you see

gap: 12px; adds 12 pixels between every row and every column.

Step 5: Set the row heights

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: repeat(3, 1fr);  gap: 12px;  grid-template-rows: 80px 80px;}
What you see

grid-template-rows: 80px 80px; makes both rows 80 pixels tall. The cards stretch to fill their taller cells.

Step 6: Line up the cards inside their cells

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: repeat(3, 1fr);  gap: 12px;  grid-template-rows: 80px 80px;  justify-items: center;  align-items: center;}
What you see

justify-items: center; and align-items: center; stop the stretching. Each card shrinks to its text and sits in the middle of its cell.

Step 7: Move the whole grid to the middle

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: repeat(3, 80px);  gap: 12px;  grid-template-rows: 80px 80px;  justify-items: center;  align-items: center;  justify-content: center;}
What you see

The columns are now a fixed 80px each, so the grid is narrower than the page, and there is space left over on the right. justify-content: center; moves the whole grid to the middle, leaving equal space on both sides.

Step 8: Plan a whole page with areas

Your code
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.layout div {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.layout {  display: grid;  grid-template-columns: 100px 1fr;  grid-template-areas:    "top top"    "menu main"    "foot foot";  gap: 8px;}.top { grid-area: top; }.menu { grid-area: menu; }.main { grid-area: main; }.foot { grid-area: foot; }
What you see

A new page: a top bar, a menu, the main stories and a footer. grid-template-areas draws the plan as three rows of words, and each item is put in its place with grid-area. "top top" makes the top bar cover both columns.

Quick notes

display: grid Turn on grid
.grid { display: grid; }

How to use

  • display: grid; Goes on the parent. Its children are placed in rows and columns.
  • The parent is the grid container, and its children are grid items.
  • Without columns set, there is one column, so nothing seems to change yet.

Examples

  1. Turn a box of cards into a grid.

    .cards {  display: grid;}
grid-template-columns The columns
.grid { grid-template-columns: repeat(3, 1fr); }

How to use

  • 90px 90px 90px Three columns, each 90px wide.
  • 1fr 2fr Two columns. The second gets twice the free space.
  • repeat(4, 1fr) Four equal columns, written the short way.
  • 200px 1fr A fixed column, then one that takes the rest.

Examples

  1. Three equal columns of cards.

    .cards {  display: grid;  grid-template-columns: repeat(3, 1fr);}
  2. A sidebar and a main area.

    .page {  display: grid;  grid-template-columns: 200px 1fr;}
  3. A photo gallery with four columns.

    .gallery {  display: grid;  grid-template-columns: repeat(4, 1fr);}
grid-template-rows The rows
.grid { grid-template-rows: 80px 80px; }

How to use

  • 80px 80px Two rows, each 80px tall.
  • auto 1fr The first row fits its content, the second takes the rest.
  • Rows you don't list are made as needed and fit their content.

Examples

  1. A header row and a content row.

    .page {  display: grid;  grid-template-rows: 80px 1fr;}
  2. Rows of tiles that are all 120px tall.

    .tiles {  display: grid;  grid-template-rows: 120px 120px;}
grid-template-areas A plan with named areas
.layout { grid-template-areas: "top top" "menu main"; }

How to use

  • "top top" One row of the plan. Each word is one column.
  • grid-area: top; Puts an item in the area named top.
  • . A dot leaves a cell empty.
  • Each name has to form a rectangle.

Examples

  1. A whole page plan: header, menu, story and footer.

    .page {  display: grid;  grid-template-columns: 150px 1fr;  grid-template-areas:    "top top"    "menu main"    "foot foot";}
  2. Place the header in its area.

    .header {  grid-area: top;}
gap Space between rows and columns
.grid { gap: 12px; }

How to use

  • 12px The same space between rows and columns.
  • 16px 8px 16px between rows, 8px between columns.
  • row-gap / column-gap Set only one of them.

Examples

  1. Space between cards.

    .cards {  gap: 12px;}
  2. More space between rows than columns.

    .cards {  row-gap: 24px;  column-gap: 12px;}
justify-items Left or right inside cells
.grid { justify-items: center; }

How to use

  • stretch Items fill the width of their cell. This is the default.
  • start Items sit at the left of their cell.
  • center Items sit in the middle of their cell.
  • end Items sit at the right of their cell.

Examples

  1. Center every item inside its cell.

    .gallery {  justify-items: center;}
  2. Line items up at the left of their cells.

    .list {  justify-items: start;}
align-items Up or down inside cells
.grid { align-items: center; }

How to use

  • stretch Items fill the height of their cell. This is the default.
  • start / center / end Items sit at the top, middle or bottom of their cell.

Examples

  1. Center items up and down in tall rows.

    .tiles {  align-items: center;}
  2. Line items up at the top of their cells.

    .cards {  align-items: start;}
justify-content Move the whole grid left or right
.grid { justify-content: center; }

How to use

  • start The whole grid sits at the left. This is the default.
  • center The whole grid sits in the middle.
  • end The whole grid sits at the right.
  • space-between / space-around / space-evenly The columns spread out, with the leftover space between them.
  • It only changes something when the columns are narrower than the container, like fixed px columns.

Examples

  1. A grid of fixed-size tiles in the middle of the page.

    .tiles {  display: grid;  grid-template-columns: repeat(3, 100px);  justify-content: center;}
  2. Fixed columns spread across the whole width.

    .buttons {  display: grid;  grid-template-columns: repeat(4, 80px);  justify-content: space-between;}
align-content Move the whole grid up or down
.grid { align-content: center; }

How to use

  • start The rows sit at the top. This is the default.
  • center The rows sit in the middle, up and down.
  • end The rows sit at the bottom.
  • space-between The rows spread out from top to bottom.
  • It only changes something when the container is taller than its rows.

Examples

  1. A small grid in the middle of a tall section.

    .hero {  display: grid;  height: 400px;  align-content: center;}
  2. Rows spread from top to bottom of a tall box.

    .board {  display: grid;  height: 300px;  align-content: space-between;}

Common mistakes

These are mistakes many beginners make. Each mini browser shows what really happens.

Columns without display: grid

The mistake
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  grid-template-columns: repeat(3, 1fr);  gap: 12px;}
What you see

grid-template-columns and gap only work on a grid container. Without display: grid;, the cards stay stacked, one per line.

Tip: Add display: grid; to the same rule first.

Writing only the number of columns

The mistake
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.card {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.grid {  display: grid;  grid-template-columns: 3;  gap: 12px;}
What you see

3 is not a column size, so the browser skips the line. The grid keeps one column, and the cards are stacked with gaps between them.

Tip: List a size for each column, or use repeat(): grid-template-columns: repeat(3, 1fr);

An area that isn't a rectangle

The mistake
body {  background-color: #F0F7FF;  font-family: Arial, Helvetica, sans-serif;}.layout div {  background-color: white;  border: 3px solid #11141A;  padding: 12px;}.layout {  display: grid;  grid-template-columns: 100px 1fr;  grid-template-areas:    "top top"    "menu main"    "main foot";  gap: 8px;}.top { grid-area: top; }.menu { grid-area: menu; }.main { grid-area: main; }.foot { grid-area: foot; }
What you see

"main" now covers an L shape: one cell in the second row and one in the third. Areas have to be rectangles, so the browser skips the whole plan. The area names no longer point anywhere, so all four items land in the same extra cell, piled on top of each other. Only the last one, the footer, can be seen.

Tip: Make each area a rectangle, like "foot foot" on the last row.

Test your knowledge

Edit the CSS on the left. Open the HTML tab to see the class names you can use. The mini browser updates as you type, and each goal gets a check mark when it's done.

No clicking needed. Each goal gets a check mark by itself once your code does it.

  1. Turn .gallery into a grid container. not done yet
  2. Give .gallery three columns with grid-template-columns. not done yet
  3. Add a gap between the photos. not done yet
  4. Center the photos inside their cells with justify-items. not done yet
Your code
What you see

Go to Exercises

Recap

  • display: grid; on the parent makes a grid. grid-template-columns and grid-template-rows set the sizes, using px, fr and repeat().
  • gap adds space between rows and columns, and grid-template-areas plans a page with named areas.
  • justify-items and align-items line up every item inside its cell, and justify-content and align-content move the whole grid inside its container.

References

Lesson content prepared by the WebCore F.E. team for beginner learners. The following references were used in preparing this lesson.

  • W3C. CSS Grid Layout Module Level 2 (official specification). Open reference
  • W3C. CSS Box Alignment Module Level 3 (official specification, gap and alignment). Open reference
  • LibreTexts. Web Site Design (2022, open textbook). Open reference