Topic 04

Grid

CSSHands-on

Flexbox lines things up in one direction. Some layouts need two: a gallery of photos, a list of cards, a page with a sidebar next to the main content, where things should line up both across and down. Grid, the CSS grid layout, arranges elements in rows and columns at the same time, and a whole card layout takes three or four lines of it.

Think of a spreadsheet. You set how wide each column is, and every cell lines up with the cells above, below and beside it, whatever is typed into them. A CSS grid works the same way: you describe the columns, and the browser puts each element into the next cell.

Columns, Rows and fr

Like flexbox, grid has a container and items: display: grid goes on the parent, and its direct children become grid items. The columns and rows of a grid are called tracks, and grid-template-columns lists the width of each column track, one value per column.

Those widths are usually written in a unit that only grid has: fr, short for fraction. One fr is one share of the space that is left over. Three columns of 1fr each split the width into three equal parts.

css/style.css
.gallery {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1rem;
}

Put six boxes inside an element with the class gallery. The browser draws two rows of three: equal columns across the full width, with 1 rem between the columns and between the rows. Nobody said anything about rows. Items fill the first row from left to right, and when it is full, the grid starts a new row on its own.

"Left over" matters when a fixed width is mixed in. With grid-template-columns: 12rem 1fr, the first column is exactly 12 rem wide and the second takes everything else, so on a wide screen the second column is wide and on a narrow one it is narrow. That is the shape of a page with a sidebar.

repeat and minmax

Writing 1fr three times is fine; writing it twelve times is not. The repeat() function says the same thing more briefly: repeat(3, 1fr) means three columns of one share each.

The minmax() function gives a track a range instead of one size: a minimum it will never shrink below and a maximum it can grow to. Combined, they describe columns that share the space but never get too narrow for a card.

css/style.css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  gap: 1rem;
}

On a wide screen this looks exactly like before: three equal columns. The difference shows when the window gets narrow. Each column stops at 200 pixels, and once three columns and their gaps no longer fit, the grid spills out past the right edge and the page scrolls sideways. That is honest behaviour, since you asked for three columns of at least 200 pixels, but it is not what a phone needs. Chapter 5 fixes it twice: once with a media query, and once with a version of this same line that decides the number of columns by itself.

Placing Items

Most of the time you place nothing: items flow into the cells in the order they appear in the HTML. You step in only for the exceptions, such as one item that should take up more room than the others.

css/style.css
.featured {
  grid-column: span 2;
}

Give the first of the six boxes the class featured. It now covers two columns of the first row, the next box takes the third column, and the rest move along to fill the rows after it. The grid keeps moving forward, putting each item in the next free space it fits.

A grid can also be described by name. The grid-template-areas property draws the layout as words in quotes, one string per row, such as a header across the top and a sidebar next to the main content, and each child is then told which named area to fill. It is a readable way to lay out a whole page, and MDN's grid guides cover it well; this book's site does not need it.

Flex or Grid?

The two tools overlap, and the choice is not a test. A workable rule of thumb: if the items run in one direction and their content decides their size, such as links in a nav or buttons in a toolbar, use flexbox. If you want rows and columns that line up with each other, such as cards, a gallery or a page layout, use grid.

They also nest happily. A grid can hold cards, and each card can use flexbox inside to push its link to the bottom. The site will end up using both: flexbox for the header you built in the last topic, grid for the cards below.

The Site's Project Cards

The Projects page holds your three project cards. Each is an article, because a card makes sense on its own, and all three sit inside one container with the class project-grid. This is the part of projects.html inside main.

Fragment: projects.html
<div class="project-grid">
  <article class="project-card">
    <h2><a href="https://example.com/budget">Budget Tracker</a></h2>
    <p>Adds up a month of spending from a spreadsheet.</p>
  </article>
  <article class="project-card">
    <h2><a href="https://example.com/recipes">Recipe Cards</a></h2>
    <p>A responsive page of recipes that prints cleanly.</p>
  </article>
  <article class="project-card">
    <h2><a href="https://example.com/weather">Weather Now</a></h2>
    <p>Shows today's forecast for any city.</p>
  </article>
</div>
css/style.css
.project-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-l);
}

The rule turns the container into a grid of three equal columns with the large spacing token between them. The cards keep the look they already have from Chapter 3; only their arrangement changes. On a laptop, the Projects page now shows the three cards side by side in one row, all the same width, their tops lined up. A fourth project added later would start a second row by itself.

On a phone, three columns do not fit. Each card gets a few words per line, and because a column never gets narrower than its longest word, the grid ends up wider than the screen and the page scrolls sideways. That is the problem Chapter 5 exists to solve, so leave it for now. To see the grid itself, open DevTools: the Elements panel shows a "grid" badge next to the container, and clicking it draws the column lines and gaps over the page, numbered.

Three tracks of 1fr: the cards fill the cells in order
1fr1fr1fr
Row 1Budget TrackerRecipe CardsWeather Now
Row 2a fourth carda fifth carda sixth card
Common Confusions
  • "Grid replaced flexbox." They do different jobs: flexbox for things in a line, grid for rows and columns that line up. Most real pages use both, often one inside the other.
  • "fr is a fixed size, like a pixel." It is a share of the space left after any fixed tracks and the gaps. The same 1fr is wide on a monitor and narrow on a phone.
  • "I have to tell every item which cell to go in." Items flow into the cells automatically, in the order of the HTML. You place only the exceptions, such as a card that spans two columns.
Why It Matters
  • Card lists, galleries and whole page layouts take a few lines of grid, and the columns line up without any measuring.
  • In Chapter 5 the same grid becomes responsive, first with one media query and then with a single line that needs no breakpoints at all.

Knowledge Check

A grid has grid-template-columns: 200px 1fr. What does the 1fr column get?

  • Exactly one fixed unit of width, set by the browser
  • All the width left over after the 200px column
  • The same 200 pixels as the column beside it
  • Only as much width as its own content needs

What does repeat(3, minmax(200px, 1fr)) describe?

  • A layout of three copies of the same grid
  • Three columns, each exactly 200 pixels wide
  • Three columns sharing the width, each at least 200px
  • As many 200-pixel columns as fit in the window

Which layout is a better fit for grid than for flexbox?

  • A row of navigation links sized by their text
  • A toolbar with one button pushed to the far end
  • Centring one heading in the very middle of a large box
  • A gallery of photos in rows and columns that line up

A grid has three columns and seven items, and no item is placed by hand. Where does the seventh go?

  • The first cell of a third row the grid adds by itself
  • Nowhere at all, since the grid has no free cell left for it
  • Into a fourth column added to the first row
  • On top of the sixth item, squeezed into that same cell

You got correct