coding character sheets

On the Grid, part 2

Paul Stefko
Jun 22, 2022
We continue exploring CSS grid, this time with tools for sizing grids dynamically and positioning items intentionally.
Tagscss html
📕 7 min.

Previously, we discussed the basics of the CSS Grid layout system. Let's continue with some more advanced features.

Dynamic Sizing

Rather than have to define a track's size either with absolute values or fractional units fr, Grid provides the minmax() function to let you define upper and lower limits for sizing. A track with minmax(100px, 1fr) will always be at least 100 pixels, but it can be more if 1fr is larger.

In addition to absolute lengths, percentages, and fractional units, minmax() can take a few special keywords. min-content and max-content refer to the minimum and maximum sizes of all items on the track based on their content. auto is more complicated, but it works similarly to those two in their respective limits.

It's also possible to have a dynamic number of tracks based on the size of the container. This requires the repeat() function with the auto-fill or auto-fit keyword for the number of repetitions. The difference between auto-fill and auto-fit is that auto-fill will keep making empty tracks based on sizing limits, while auto-fit will collapse any empty tracks. (If you're not sure which is right for you, try both and see what changes.)

So, the following code...

.grid-multi-col {
display: grid;
grid-template-columns: repeat(auto-fit, 100px);
}

...will create as many 100-pixel column tracks as will fit in the available space. If the container is 450 pixels wide, this means it will have four columns. If you have fewer than four grid items, however, any empty tracks will collapse.

You can combine this use of repeat() with minmax() to create a dynamic number of dynamically sized tracks. The browser will add as many tracks of the minimum size in minmax() as will fit in the grid container, then it will let those tracks expand as much as possible to fill the remaining space, up to the maximum size in minmax(). So the following code...

.grid-dynamic-col {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px,1fr));
}

...will create as many 200-pixel-wide column tracks as it can in the available space, but once it can't fit any more, it will let the tracks it's made expand until each one takes an equal share of the container. Resizing the container— say by resizing the browser window—will change the number of columns and the width of each column. (To see this in action, check out this example from Grid By Example by Rachel Andrew.)

Positioning Items

In our last discussion, I mentioned that the browser has invisible, numbered lines around each track. Those lines are useful when we want to directly positition an item on the grid, rather than letting the browser do it automatically. They also let us define grid items that span multiple columns and/or rows.

These lines begin at 1 at the start of the first track in a given dimension. The count goes up by 1 after each track, so the first column always starts at line 1 and ends at line 2. The browser also lets you count backward from the end of the final track by also numbering the lines with negative values in the opposite direction. So the final column of a grid always starts with -2 and ends with -1. (The same line always has two numbers, one positive and one negative.)

You can give a grid item the grid-column-start, grid-column-end, grid-row-start, and grid-row-end properties to define its exact location on the grid. Each of these takes one of those line numbers as its value. You can also use the grid-column and grid-row shorthand properties, seperating the two values with a slash /. So, an item with grid-column: 2 / 3 will always be placed in the second column (between lines 2 and 3).

To make a grid item span multiple tracks, just make it end more than one line after it starts. So, an item with grid-row: 1 / 3 would span the first and second rows, starting at line 1 and ending at line 3. If you want the item to span the entire grid in a given direction, use 1 / -1 as the value.

But that's not all! CSS lets you name areas of your grid for easier reference. When you set up your grid-template-columns or grid-template-rows properties, you can name grid lines by putting [*-start] and [*-end] between your track sizes. Here's an example (with line breaks for readability):

.grid-named-cols {
display: grid;
grid-template-rows:
[header-start] 200px [header-end]
1fr
[footer-start] 150px [footer-end];
}

This creates three rows in our grid: a 200-pixel row, then a flexible row, and finally a 150-pixel row. Lines 1 and 2 (the start and end of the first row) have been renamed "header", while lines 3 and 4 (the start and end of the last row) have been renamed "footer."

To place an item in a named area, you can use the grid-column and grid-row properties, replacing numbers with the name. But a faster way is to use the grid-area shorthand property. In our example above, I can give an item grid-area: header, and it will be placed in the first row.

You can also give lines more than one name. Say we wanted to refer to the middle row in our example as "content." We can just add content-start and content-end into our code from before:

.grid-named-cols {
display: grid;
grid-template-rows:
[header-start] 200px
[header-end content-start] 1fr
[content-end footer-start] 150px [footer-end];
}

Named lines can span multiple tracks, and you can use the same names in both grid-template rows and grid-template-columns to create areas that span both rows and columns. At that point, though, your areas are probably getting complex enough that you'll want to use our final trick.

The grid-template-areas property lets you define arrangements of named areas in a "text art" style. You define each row as a string surrounded by quotation marks " and containing a name for each column in that row (without "-start" or "-end"). The result names all of your areas at once. (If you don't need to name a particular cell, you can put a period . to hold its place.) You can even use as many spaces as you want to make everything line up nicely.

Here's a big example to show how all this works together (outlines added to make areas more obvious):

.grid-names {
display: grid;
grid-template-columns: 100px 1fr 1fr 100px;
grid-template-rows: 2em 1fr 2em;
grid-template-areas:
"left left right right"
". content content ."
"foot foot foot foot";
}
.grid-names div {
border: 1px solid gray;
}
.left {
grid-area: left;
}
.right {
grid-area: right;
text-align: right;
}
.content {
grid-area: content;
}
.foot {
grid-area: foot;
text-align: center;
}
<div class="grid-names">
<div class="left">Left Header</div>
<div class="right">Right Header</div>
<div class="content">
Sint cillum id fugiat est minim ut nulla ad
proident adipisicing. Officia minim ad quis id ut
ex ad amet deserunt velit duis exercitation.
Dolore est fugiat consequat ex exercitation. Dolore
consequat ipsum ex aute nisi. Qui dolore duis duis
tempor reprehenderit pariatur dolore. Non labore
eiusmod duis et duis anim. Dolore esse ad cupidatat
nulla excepteur fugiat in nisi ut sit enim.
</div>
<div class="foot">Footer</div>
</div>
Left Header
Right Header
Sint cillum id fugiat est minim ut nulla ad proident adipisicing. Officia minim ad quis id ut ex ad amet deserunt velit duis exercitation. Dolore est fugiat consequat ex exercitation. Dolore consequat ipsum ex aute nisi. Qui dolore duis duis tempor reprehenderit pariatur dolore. Non labore eiusmod duis et duis anim. Dolore esse ad cupidatat nulla excepteur fugiat in nisi ut sit enim.
Footer

Conclusion

There's still more cool stuff we can do with CSS Grid, so we'll come back to it again in the next post. Until then, play around with layouts, and see what you can come up with!