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.
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, em
s, 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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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:
- The why and where of Grid Layout
- Terminology and basics
- Grid track sizing (this part)