Advanced Grid Layout and Functions

Demo starter files

This page is an introduction to a few of CSS Grid's more advanced abilities.

Auto Sizing Columns

repeat()

The repeat() function is a quick, convenient shortcut. If you need several columns of the same size in your grid template...

/* 12 column grid */
.grid-container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

repeat() saves you a bit of typing.

/* 12 column grid */
.grid-container {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
}

You can also use it mixed with grid tracks of other sizes:

.grid-container {
    display: grid;
    grid-template-columns: 1fr repeat(3, 150px) 1fr;
}

minmax()

minmax() is effectively min-width and max-width for grid tracks (columns and rows). This is very similar to setting min-width and max-width on a normal element.

/* Expanding main column, up to 36em */
grid-container {
    display: grid;
    grid-template-columns: 1fr [main-start] minmax(auto, 36em) [main-end] 1fr;
}

auto-fill / auto-fit

Using minmax() we can set limits on the size of grid items separately from the size of the overall grid container. Is it possible, then, to tell grid to repeat() as many times as possible in the container?

Yes!

By combining these two functions with the special keywords auto-fit or auto-fill, we can tell the Grid algorithm, "figure out how many columns fit in the available space."

Dynamic, responsive grid in one line of code - no media queries!

Let's switch to the demo files and take a look at this in action.

The difference between auto-fit and auto-fill is relatively subtle. Both values create as many columns as will fit in the available space, even if there's no more content to put in them. The difference is whether the leftover, empty columns should take up space, or be collapsed.

Using the dev tools grid inspector on these two figures will show the difference. Most of the time you'll probably use auto-fit.

.grid-container {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(3em, 1fr));
}
  • 1
  • 2
  • 3
  • 4
  • 5
Using the grid inspector you can see additional columns are created when there's room, even if there's no more content to put in them.
.grid-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(3em, 1fr));
}
  • 1
  • 2
  • 3
  • 4
  • 5
Using the grid inspector you can see additional columns (numbers) are still created, but collapsed.

Keep in mind this difference is only visible when the grid only has one row.

Nesting Grids

It's entirely possible for a grid item to also be a grid container. Here's an example:

<div class="grid-container">
    <section>...</section>
    <section>...</section>
    <ul>
        <li>...</li>
        <li>...</li>
        <li>...</li>
        <li>...</li>
    </ul>
</div>

We can use display: grid for the whole page layout, and also have, say, a grid of image thumbnails.

/* Whole page layout */
.grid-container {
    display: grid;
}

/* This grid item is also a grid container */
ul {
    display: grid;
}

CSS tries to separate the visual layout of a page from the structure of its content. In reality there will always be a least some things you need to do with your HTML solely to achieve the layout and styling you want.

One such case is with CSS Grid. Since the grid relies on a direct parent-child relationship, it's difficult to get elements that are nested further down to participate in the same grid template.

In the example above, let's say the list items are not image thumbnails, but other content that you want to be part of the same top level grid. The easiest thing to do would be to flatten your HTML structure. Turn the list items into additional sections or divs.

Unfortunately this can lead to poor markup, since we're turning content that semantically should be list items into something else, just for the sake of the layout.

In cases like this, there's a new display property that's quickly being adopted in modern browsers. It's called display: contents.

When you set display: contents on an element, it effectively disappears from the document structure (as far as CSS is concerned), and its children get "promoted" one level.

/* Whole page layout */
.grid-container {
    display: grid;
}

/* Setting this to display: contents removes it from the CSSOM and "promotes" its child elements */
ul {
    display: contents;
}

This also works for flexbox, which requires the same direct parent-child relationship.

display: contents is a great solution that helps us keep well structured HTML in certain situations, while building the layouts we want. Eventually there will be an entire new CSS spec, display: subgrid, that will address other similar challenges.