Grid Tidbits part 3: grid track sizing

This post will examine some of the finer points of sizing grid tracks (a.k.a. rows and columns) in CSS Grid Layout. Flexible sizing, the repeater function, the minmax function – oh my!

To play along with the examples in this post, I recommend that you download and fire up Chrome Canary, since that browser has the most up-to-date implementation.

Recap

In the previous tidbit, we used some very simple markup to represent a grid container and three child items.

<div class="grid-container">
  <div class="grid-item-a">A</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
</div>

We're going to keep this markup, but play with the sizing. The grid track definitions we started with looked like this:

.grid-container {
  display: grid;
  grid-template-columns: 50% 50%;
  grid-template-rows: auto auto;
}

The above means we created a 2 ✕ 2 grid template, where the two columns each take up 50% of the width, and the two rows automatically adjust their height to fit the tallest content inside. If we just let the items position themselves with the automatic placement algorithm, A and B end up in the first row, and C ends up in the bottom left corner.

A two by two grid with three items (labelled A,B,C), two on the first row and one on the second.

The 2 ✕ 2 grid from part 2 (JSBin link for figure 1)

The mental shift to understand grid layout is that the sizing mechanics of the grid resides mostly in the grid track definitions, rather than in the items themselves. We can use loads of types of measurements to size tracks – percentages, ems, pixels, viewport units etc. But there are more exciting possibilities in the grid layout spec – let’s jump straight in!

Getting flexible – the fr-unit

The Grid Layout spec introduces a new unit for flexible sizing. The fr unit stands for fraction of remaining space. It distributes the space left when any tracks sized with auto, percentages, ems, pixels etc have been calculated. If you know your flexbox, it's basically the same thing as a flex-grow factor, with a 0 flex-basis.

If we change the first column to be 5em and the second column to be 1fr, the second column will receive any space left above 5em.

.grid-container {
  display: grid;
  grid-template-columns: 5em 1fr;
  grid-template-rows: auto auto;
}

The two by two grid, where the left column is narrower than the right

The updated grid, where the right column takes up any space left above the 5em width of the left column. (JSBin link for figure 2)

You may be wondering what the 1 in 1fr actually stands for. If you’re comfortable with flexbox already, you may have a reasonably clear picture, but it doesn’t hurt to actually get into the details.

For example, what happens if the right column would be sized to 2fr? Would it then be two times as wide as the remaining space, and cause overflow? No. Mathematically, “fraction of available space” means that the second column will receive(flex number * available space) / combined number of flex units. This means that if there’s 100 pixels of available space, the right column will be (2 * 100) / 2 pixels wide, so still 100 pixels. It’s like mixing drinks: no specific measurements, but rather “2 parts tequila, 1 part whisky, 1 part bitter tears” (That would probably be a horrible cocktail. Then again, I’m not a licensed mixologist).

If we were to add another column also sized to 1fr, the middle and right columns would be equally wide – each is 1 fraction of the available space, i.e. 1/2.

.grid-container {
  display: grid;
  grid-template-columns: 5em 1fr 1fr;
  grid-template-rows: auto auto;
}

The three by two grid, where the second and third columns are equally wide. The second row is empty and invisible

The B and C columns are now equally wide. Note that the second row in the grid is now empty, and collapses down to 0 height. (JSBin link for figure 3)

If we use different flexible lengths for the two tracks, we can see more clearly how the units relate to each other.

.grid-container {
  display: grid;
  grid-template-columns: 5em 2fr 1fr;
  grid-template-rows: auto auto;
}

The three by two grid, where the second column is twice as wide as the third. The second row is empty and invisible

The B column is now twice as wide as C. (JSBin link for figure 4)

There’s three units competing for space in total (2fr + 1fr), so two thirds of the remaining space (after the first column is sized) gets allocated to the second column, and one third to the second column.

Repeating grid tracks

If you’re dealing with a more complex grid than just a handful of columns, it get’s tedious to write out repeating columns of the same size. Luckily, the grid spec has this sorted: you can use the repeat() functional notation. If we have a grid of 24 equal width columns (for example), you can just repeat a 1fr track 24 times.

<div class="grid-container">
  <div class="grid-item-a">A</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
  <div class="grid-item-a">A</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
  <!-- ...and so on, 24 items -->
</div>
.grid-container {
  display: grid;
  grid-template-columns: repeat(24, 1fr);
  grid-template-rows: auto auto;
}

The three by two grid, where the second column is twice as wide as the third. The second row is empty and invisible

24 items in 24 equal width columns. (JSBin link for figure 5)

You can mix and match repeated tracks with regularly declared tracks, in case some of them are different. If the first and last columns are of a different measurement, the track list for columns could look like this.

.grid-container {
  display: grid;
  grid-template-columns: 5em repeat(22, 1fr) 5em;
  grid-template-rows: auto auto;
}

Minimum and maximum sizes

Since we're sizing grid tracks rather than elements in the DOM, we can't use the min-width, max-width, min-height and max-height properties to size them. Instead, the Grid Layout spec introduces a functional notation for this purpose, appropriately called minmax().

For instance, we might want the leftmost column to take up 20% of the width, but with a minimum width of 5em.

.grid-container {
  display: grid;
  grid-template-columns: minmax(5em, 20%) 1fr 1fr;
  grid-template-rows: auto auto;
}

Intrinsic sizing keywords and auto sizing

So far, we have declared that the row tracks have an auto height. What does that mean? Well, we’ve already concluded that it means that the track collapses down to 0 height if the row is empty. If there are items placed in the row, it will expand to fit them. In simplified terms, this expand-to-fit behavior means that it will be as tall as the tallest grid item, depending on how the items themselves are sized.

We can also use the keywords from the Intrinsic & Extrinsic Sizing module to gain even more fine-grained control over how we size the tracks. If we’re dealing with a column containing some short text, we may want to size it so that it has a maximum size corresponding to the max-content width.

<div class=";grid-container";>
  <div class="grid-item-a">Hello world</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
</div>
.grid-container {
  background-color: #E6CAD6;
  display: grid;
  grid-template-columns: minmax(5em, max-content) 1fr 1fr;
  grid-template-rows: auto auto;
}

A three column grid, where the first column contains the words ”hello world.”

As long as there’s any space left, the first column will now expand to fit the words “Hello world. (JSBin link for figure 6)

If we add a fourth item to the grid, it will end up on row two (via the rules of auto placement – don’t worry, we’ll get back to that in later tidbits). If the content inside that item is even wider, then the whole track will have a larger min-content size. So: max-content means “the largest max-content item inside the track”.

<div class="grid-container">
  <div class="grid-item-a">Hello world!</div>
  <div class="grid-item-b">B</div>
  <div class="grid-item-c">C</div>
  <div class="grid-item-d">Hello big world!</div>
</div>
.grid-item-d {
  background-color: #274461;
}

A three column grid, where the first column contains the words ”hello world.”

The “D” item pushes on the max-content size of the first column (JSBin link for figure 7)

To me personally, track sizing in the grid layout module is one of the places where I’ve actually seen immediate use for the intrinsic sizing keywords in CSS. (On the other hand, I suspect that they're highly useful elsewhere, but I haven’t worked them into my thinking yet.) These keywords have been around for a while, but support is still spotty, with mostly prefixed implementations.

Wrap-up

That’s it for the first pass of sizing grid tracks! There’s more to come – we haven’t even gotten started on gutters, named lines or template areas yet… These first posts have been slightly longer than anticipated, but as we get to grips with the basics, we can discuss other concepts in shorter form ahead. So stay tuned for more tidbitty tidbits!

The tidbits so far:

  1. The why and where of Grid Layout
  2. Terminology and basics
  3. Grid track sizing (this part)