Understanding CSS Grid: Creating A Grid Container
This is the start of a new series here at Smashing Magazine concentrating on CSS Grid Layout. While Grid has been available in browsers since 2017, many developers won’t have had a chance to use it on a project yet. There seem to be a lot of new properties and values associated with CSS Grid Layout. This can make it seem overwhelming. However, quite a lot of the specification details alternate ways to do things, meaning that you don’t have to learn the entire spec to get started. This series aims to take you from grid novice to expert — with lots of practical usage tips along the way.
This initial article will cover what happens when you create a grid container and the various properties that you can use on the parent element to control that grid. You will discover that there are several use cases that are fulfilled only with the properties that you apply to the grid container.
In this article, we will cover:
- Creating a grid container with
display: grid
ordisplay: inline-grid
, - Setting up columns and rows with
grid-template-columns
andgrid-template-rows
, - Controlling the size of implicit tracks with
grid-auto-columns
andgrid-auto-rows
. - Part 1: Creating A Grid Container
- Part 2: Grid Lines
- Part 3: Grid Template Areas
Creating A Grid Container
Grid, like Flexbox, is a value of the CSS display
property. Therefore to tell the browser that you want to use grid layout you use display: grid
. Having done this, the browser will give you a block-level box on the element with display: grid
and any direct children will start to participate in a grid formatting context. This means they behave like grid items, rather than normal block and inline elements.
However, you may not immediately see a difference on your page. As you haven’t created any rows or columns, you have a one-column grid. Enough rows are being generated to hold all of your direct children, and they are displaying one after the other in that single column. Visually they look just like block elements.
You will see a difference if you had any string of text, not wrapped in an element, and a direct child of the grid container, as the string will be wrapped in an anonymous element and become a grid item. Any element which is normally an inline element, such as a span, will also become a grid item once its parent is a grid container.
The example below has two block-level elements, plus a string of text with a span in the middle of the string. We end up with five grid items:
- The two
div
elements, - The string of text before the span,
- The span,
- The string of text after the span.
If you inspect the grid using the Firefox Grid Inspector, you can see the five-row tracks that have been created for the items.
You can also create an inline grid by using display: inline-grid
; in this case, your grid container becomes an inline-level box. However, the direct children are still grid items and behave in the same way as grid items inside a block-level box (it is only the outer display type). That is why the grid container behaves the way it does above when it is alongside other boxes on the page.
This next example has a grid followed by a string of text, as this is an inline-level grid, the text can display alongside it. Inline-level things do not stretch to take up all the space in the inline dimension in that way that block-level things do.
Note: In the future, we will be able to better describe our layout by using display: block grid
in order to create our block-level container, and display: inline grid
to create an inline-level container. You can read about this change to the display specification in my article, “Digging Into The DIsplay Property: The Two Values Of Display”.
Columns And Rows
To get something that looks like a grid, we will need to add columns and rows. These are created using the grid-template-columns
and grid-template-rows
properties. These properties are defined in the spec as accepting a value called a track-list.
"These properties specify, as a space-separated track list, the line names and track sizing functions of the grid. The grid-template-columns property specifies the track list for the grid’s columns, while grid-template-rows specifies the track list for the grid’s rows."
Some valid track-list values are as follows:
grid-template-columns: 100px 100px 200px; | Creates a three-column grid: The first column is 100px, the second 100px, the third 200px. |
grid-template-columns: min-content max-content fit-content(10em) | Creates a three-column grid: The first column is the min-content size for that track, the second the max-content size. The third is either max-content unless the content is larger than 10em, in which case it is clamped to 10em. |
grid-template-columns: 1fr 1fr 1fr; | Creates a three-column grid using the fr unit. The available space in the grid container is divided into three and shared between the three columns. |
grid-template-columns: repeat(2, 10em 1fr); | Creates a four-column grid with a repeating pattern of 10em 1fr 10em 1fr as the track-list in the repeat statement is repeated twice. |
grid-template-columns: repeat(auto-fill, 200px); | Fills the container with as many 200px columns as will fit leaving a gap at the end if there is spare space. |
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | Fills the container with as many 200px columns as will fit then distributes the remaining space equally between the created columns. |
grid-template-columns: [full-start] 1fr [content-start] 3fr [content-end] 1fr [full-end]; | Creates a three-column grid: The first and third columns have 1 part each of the available space while the middle column has 3 parts. The lines are named by putting line names in square brackets. |
As you can see there are many ways to create a track listing! Let’s have a look at exactly how these all work, with a few tips in terms of why you might use each one.
Using Length Units
You can use any length units, or a percentage to create your tracks. If the size of the tracks adds up to less than is available in the grid container, then by default the tracks will line up at the start of the container and the spare space will go to the end. This is because the default value of align-content
and justify-content
is start
. You can space out the grid tracks, or move them to the end of the container using the alignment properties, which I explain in detail in my article “How To Align Things In CSS”.
You can also use the keywords min-content
, max-content
and fit-content()
. Using min-content
will give you a track that is as small as it can be without causing overflow. Therefore, when used as a column size, the content will softly wrap wherever possible. The track becoming the size of the longest word in the column or largest fixed-size element.
Using max-content
will cause the content to not do any soft-wrapping at all. In a column, any string of text will unwrap which may cause overflow.
The fit-content
keyword can only be used by passing in a value. That value becomes the max that this track will grow to. Therefore, the track will act like max-content
with the content unwrapping and stretching out until it hits the value you passed in. At that point, it will start wrapping as normal. So your track may be smaller than the value you pass in, but never larger.
You can find out more about sizing in Grid and other layout methods in my article “How Big Is That Box? Understanding Sizing In CSS Layout”.
If you end up with tracks that take up more space than you have in your container, they will overflow. If you use percentages then, as with percentage-based float or flex layouts, you will need to take care that the total percentage is not more than 100% if you want to avoid overflow.
The fr
Unit
Grid Layout includes a method that can save you calculating percentages for yourself — track sizing with the fr
unit. This unit isn’t a length, and therefore can’t be combined with calc()
; it is a flex unit and represents the available space in the grid container.
This means that with a track-list of 1fr 1fr 1fr
; the available space is divided into three and shared evenly between the tracks. With a track-list of 2fr 1fr 1fr
, the available space is divided into four and two parts are given to track one — one part each to tracks two and three.
Something to watch out for is that what is being shared out by default is available space which is not the total space in the container. If any of your tracks contain a fixed-size element or a long word that can’t be wrapped, this will be laid out before the space is shared out.
In the next example, I removed the spaces between the words of ItemThree
. This made a long unbreakable string so space distribution happens after the layout of that item has been accounted for.
You can mix the fr
unit with fixed length tracks, and this is where it becomes very useful. For example, you could have a component with two fixed-sized columns and a center area that stretches:
You can have a component with one track set to fit-content(300px)
and the other to 1fr. This makes for a component that can have something smaller than 300px in the first track, in which case it only takes the space it needs and the fr
unit expands to take up the rest of the space.
If you add something larger (such as an image with max-width: 100%
), the first track will stop growing at 300px and the fr
unit takes the rest of the space. Mixing the fr
unit with fit-content is a way to make some very flexible components for your site.
The repeat() Function
Using repeat()
in your track-list can save typing out the same value or values over and over again. For example the following two lines are the same:
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(12, 1fr);
When using repeat()
the value before the comma is the number of times to repeat the track-list that comes after the comma. That track-list can be multiple values. This means you can repeat a pattern of tracks.
You can use the repeat()
function for part of a track-list. For example, the following line would give you a 1fr track, 3 200px tracks, and a final 1fr track.
grid-template-columns: 1fr repeat(3,200px) 1fr
In addition to a number before the comma to indicate a fixed number of times to repeat the pattern, you can also use the keywords auto-fill
or auto-fit
. Using one of these keywords means that instead of a fixed number of tracks, your grid container will be filled with as many tracks as will fit.
Using a fixed-length unit means that, unless the container is able to be exactly divided by that size, you will end up with some spare space remaining. In the example above my container is 500px wide, so I get two 200px tracks plus space at the end.
We can use another grid function to make the value a minimum, with any spare space distributed across all of the tracks. The minmax()
function takes a minimum and a maximum size. With a minimum of 200px and a max of 1fr, we get as many 200px tracks as will fit and because the max is 1fr, which we already know will share out the space evenly, the extra is distributed across the tracks.
I mentioned there are two possible keywords: auto-fill
and auto-fit
. If you have enough content to fill the first row of cells, then these will behave in exactly the same way. If, however, you do not (e.g. if we remove all but one item inside the container above), then they behave differently.
Using auto-fill
will maintain the available track sizing even if there is no content to go into it.
If, instead, you use auto-fit
, the empty tracks will be collapsed:
By using the Firefox Grid Inspector, you can see that the tracks are still there, but have been collapsed to zero. The end line of our grid is still line 3 as we can fit two tracks.
Named Lines
My final example above used the named lines approach. When using Grid. you always have line numbers, however, you can also name the lines. Lines are named inside square brackets. You can have multiple names for one line; in that case, a space separates them. For example, in the following track-list, all of my lines have two names.
grid-template-columns: [main-start sidebar-start] 1fr [sidebar-end content-start] 4fr [content-end main-end]
You can name your lines anything that you like, except the word span
as that is a reserved word due to being used when placing items on the grid.
Note: In the next article in this series, I’ll be talking more about line-based placement and how named lines are used. In the meantime, read my article on “Naming Things in CSS Grid Layout” to help you learn more on the topic.
The Explicit Vs The Implicit Grid
When creating a grid using grid-template-columns
and grid-template-rows
with a track-list, you are creating what is referred to as the explicit grid. This is the grid you have defined which has the sizing you have chosen for each track.
If you have more items than will fit, or place an item so it falls outside of the bounds of the grid you have created, Grid will create tracks in the implicit grid. These implicit tracks will be auto-sized by default. We saw this implicit grid in action when I declared display: grid
on the parent element and grid created rows, one for each item. I didn’t define these rows, but as there were grid items, the row tracks were created to give them somewhere to go.
You can set a size for implicit rows or columns by using the grid-auto-rows
or grid-auto-columns
properties. These properties take a track-listing, so if you want all implicit columns to be at least 200 pixels tall but grow if there is more content, you could use the following:
grid-auto-rows: minmax(200px, auto)
If you want the first implicit row to be auto-sized, and the second to be min-content
sized, and so on (until all of the grid items have been accommodated), you can pass in multiple values:
grid-auto-rows: auto 100px
Using A Grid With Auto-Placement
Creating a grid (and allowing the browser to auto-place items) gets you a long way in terms of the useful patterns you can achieve. We have not yet looked at placing items on the grid, but many layouts that make use of Grid don’t do any placement. They simply rely on placing the items in source order — one in each grid cell.
If you are new to CSS Grid, then playing with different track sizes and seeing how the items place themselves into the cells you create is a great way to start.
- Part 1: Creating A Grid Container
- Part 2: Grid Lines
- Part 3: Grid Template Areas
Further Reading
- In Praise Of The Basics
- How To Build A Magazine Layout With CSS Grid Areas
- Useful DevTools Tips and Tricks
- How To Design Effective Conversational AI Experiences: A Comprehensive Guide