Skip to content

Getting started with Grid

Block level elements stack on top of each other, which works well enough, but we can’t create very exciting layouts using them.

CSS has several layout features that you can use, and the two that you’ll use the most often are Grid and Flexbox. They are both very powerful features. Each one has it’s own strengths, which we want to lean into when creating layouts, and which we’ll be exploring as we dive into both of them in the coming lessons.

Others include multi-column, which has more niche use cases, floats, which still serve a purpose, but shouldn’t be used for creating layouts, and positioning, which again, shouldn’t be used for creating layouts.

One of the problems with Grid is that it can be very complicated. Just because it can be doesn’t mean that it has to be, though. For this course, I want to focus on the 20% of Grid that you’ll use 95% of the time.

First, any time we want to use Grid, we have to enable it by declaring display: grid;.

This will change the parent element into a Grid Container.

On the outside, it will stay a block level element, but the direct children will be turned into Grid Items. This is where the concept of layout modes comes in, because it doesn’t matter what that element is, it now lives by rules of being a Grid Item (more on that soon).

In the example above, everything simply stacked… which is a lot like the way regular block elements work, and doesn’t seem very useful. It is important to note that the items are just stacked, however. Grid is creating a new row for each one, and each item is living in the cell that has been created.

Still, we generally need more than a few rows. There are two properties you will use almost every time you use Grid:

  • grid-template-columns
  • gap

You can do a lot with those two properties (along with display: grid of course).

As the name implies grid-template-columns creates columns. To define those columns, all we need to do is write out a space-separated list of the size we want each column to be, like so:

.grid {
display: grid;
grid-template-columns: 100px 200px 100px;
}

The above example would give you three columns, with the left and right ones 100px wide, and the middle one 200px wide.

They can be any size you want and can use a mix of lenth units if you’d like:

.grid {
display: grid;
grid-template-columns: 100px 200px 50%;
}

We can also declare rows using grid-template-rows and it works the same way as defining columns, with one very big difference: Grid will not create new columns by default, but it will create new rows if needed.

First, the Grid Items will be placed in the cells created for the columns. If all those column cells are full, the next item will be placed in a new implicitly created row.

The gap property allows us to add space between our columns and rows, instead of relying on margin place on the items themselves.

This is much better than using margins as it only places the space between the Grid Items and not on the outside of them.

There is a special unit that can only be used when creating columns and rows with Grid: the fr unit, which distributes a fraction of the leftover space.

You can use larger or smaller values than 1 when using the fr unit, but I find using 1fr is by far the most common unit that I’ll use.

If you have multiple columns using the fr unit with different values (such as 1fr 2fr 4.5fr), it changes how the space is distributed. If you are familiar with flex-grow, it works the same way (if you aren’t familiar with it, don’t worry, we’ll be talking about it later on).

The fr unit seems to work a lot like % at first glance.

For example, I can have equal columns quite easily by using percentages, like so:

.grid {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
}

That works great, but if we were to add a gap, we’d have a problem.

When we use percentage, it’s based on the size of that element. If we don’t have a gap, the 25% works because 100 / 4 = 25, perfect!

As soon as we add a gap, each column is the same size as before, but now we have the extra gaps in there too, and problems ensue.

If we use fr, we don’t have to worry about any issues.

If you are creating columns that are all going to be the same size, you can use the repeat() function.

For example, if you want three columns:

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

I’ll do this quite often with the help of a media query or container query, enabling the columns only when there is enough room for them:

.three-columns {
display: grid;
@media (width > 780px) {
grid-template-columns: repeat(3, 1fr);
}
}

In the example below, we have a mix of different types of elements, but add a display: grid to the parent, and you’ll see how all of those differences go out the window.

We’re going into a new Layout Mode, so the rules have changed, and those items are simply Grid Items now.

The other important thing is that Grid is creating a new row for direct child.

Because they’re in a new Layout Mode, there are some new rules that Grid Items live by:

  • When % is used for the inline-size and block-size, along with width and height, it is a percentage of the cell the element is in, rather than the parent.
  • Margins no longer collapse between each other, or the parent.
  • You can use z-index without having to declare a position first.
  • If they have declared columns and rows, absolute positioning will be relative to those cells.