The most common thing you learn in CSS Grid is usually related to the grid container and rather than the grid items. A generic grid definition applied to the grid container is enough for a basic layout structure. However, when you need more control over the contents of the grid, the grid container is limited its uses.
For example, you may want a 4 x 2 grid but the first grid item should take up column 1 and 2 as well as row 1 and 2. Or maybe you want an item to span till the last grid column track when you have no idea what the runtime total number of the grid column track is.
Each grid item’s size is predefined and you need to find a way to size them relatively to other items in the grid container.
In this tutorial you’ll explore placing, spanning, and density in CSS Grid.
Everything in the browser has a default style, for example, 0
or auto
. There could also be other defaults that you need to be aware of before adjusting for custom values. When you have a grid, the grid items have placement values defined by grid-[x]-start
and grid-[x]-end
(where x
can be column
or row
). The value is auto.
When you see a grid layout, it can help to remember that each item in that grid has a placement value no matter how symmetric the flow looks:
.container {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(5, 1fr)
}
.item {
grid-column-start: auto; /_ default _/
grid-column-end: auto; /_ default _/
grid-row-start: auto; /_ default _/
grid-row-end: auto; /_ default _/
}
Let’s adjust these default values starting with columns:
.item:nth-child(1) {
grid-column-start: 1;
grid-column-end: 5;
}
.item:nth-child(1)
grid-column-start: 1;
grid-column-end: 5;
See the full code here.
The same rules apply to row-placing:
.item:nth-child(22) {
grid-row-start: 1;
grid-row-end: 4;
}
However, grid-row-[x]
will reset the grid item default placement to start at column line 1 and row line 1, then the placement spanning will occur.
You’ll see in this code that line 22
left its spot and moved up to line 1
before spanning.
If you want it to stay at its original column track, then you have to explicitly state that:
.item:nth-child(20) {
grid-column-start: 3;
grid-row-start: 5;
grid-row-end: 10;
}
You can provide only start
or end
—you do not have to provide the placing properties in pairs. You can just provide one and the rest will stay as auto
(default). The tricky thing to watch out for is that if you change only the value of grid-[x]-start
, the grid item will start at the line, not the track:
.item:nth-child(1) {
grid-column-start: 5;
}
On the other hand, if you specify end
only, it will start from the specified end value and span the grid inversely. For example, if you tell item 10
to end at 3
, it will start from the nearest next line 2
and draw to line 3
:
.item:nth-child(10) {
grid-column-end: 3;
}
You can see all the code here.
There’s also shorthand syntax for grid-[x]-start
and grid-[x]-end
that allows you to do away with the -start
and -end
code:
.item {
grid-column: [start] / [end];
grid-row: [start] / [end];
}
Here are some examples that can replace the code samples we have written so far:
.item {
grid-column: 1 / 5; /__ Line 1 to 5 /
grid-row: 1 / 4; /*_ Line 1 to 4 __/
grid-column: 5 / auto; / Line 5 to 6 *_/
grid-column: auto / 3; /_ Line 2 to 3 _/
}
We have been using the word “span” to describe the number of tracks a placement should occupy. When we say line 1
to 5
, we are saying the grid item should span from 1
to 5
. I usually refer to this as implicit spanning.
There is a span
keyword that serves as a value. When this is used, you can refer to it as explicit spanning. Placing and spanning are flexible enough that you can use both implicit and explicit spanning as value to a single property.
Let’s start with looking at how we can span an item across a column track:
.item:nth-child(1) {
grid-column: span 5;
}
This is an alternative to the first example we wrote:
.item:nth-child(1) {
grid-column: 1 / 5;
}
But we can include additional detail:
.item:nth-child(1) {
grid-column: span 2 / 5;
}
Here we end at 5
and the span 2
tracks backward.
Another example:
.item:nth-child(1) {
grid-column: 2 / span 2;
}
Here we start at column line 2
and end at column line 4
(after 2
jumps).
Everything you have learned so far in this tutorial about rows applies without exception:
.item:nth-child(1) {
grid-column: 2 / span 2;
/_ highlight line_/
grid-row: span 5
}
We are still spanning the first time, but then we’re spanning on the row axis. The browser will draw the box down to occupy five tracks.
Recall that we have explicitly defined our grid to have 5
columns. We can span or place an item from column 6
up like the following:
.item:nth-child(1) {
grid-column: span 10; /_ 1 _/
grid-column: 1 / 10; /_ 2 _/
grid-column: 7 / 10; /_ 3 _/
grid-column: 1 / span 10; /_ 4 _/
}
Implicit tracks will be created to accommodate them.
Negative integers are as useful as the positives—they inverse the placement or spanning. Hence, instead of starting from the first column or row, the placement or spanning will start from the last column or row.
These code snippets are direct opposites:
.item:nth-child(1) {
grid-column: 1 / 5
}
.item:nth-child(1) {
grid-column: -1 / -5
}
Since we are starting at the end to draw backward as I mentioned above, there will be room for item 2
in column 1
so it gets pushed down. We will look at using density to fill up these spaces created in such cases (if the content is not symmetric).
There is a way that you can span to the end of a column or row without needing to know how many columns are defined by the grid container. This is useful when you are using auto-fill or auto-fit in defining a dynamic grid:
.item:nth-child(1) {
grid-column: 1 / -1
}
Specifying -1
for row end or column end will make the grid item span till the end of grid starting at what ever start you provided (in this case line 1).
However, this does not work on implicit grids. Therefore since we defined only column and row in the grid container, this will not do anything:
.item:nth-child(1) {
grid-row: 1 / -1;
}
For it to work, you would have to give an explicit row definition to the grid container. For example:
.container {
grid-template-rows: repeat(10, 30px);
}
In the previous examples, you will have seen some placement or spanning that caused empty spaces scattered in the middle of a grid.
You can close these spaces using grid-auto-flow
property on the grid container to close up those white spaces:
.container {
grid-auto-flow: dense;
}
One thing you should be aware of is that if you have symmetric content that needs to follow an order, making the flow dense will distort that order. This is a trade-off you have to make if you want a compact design while still placing grid items irregularly.
Notice how after placing item 1
at the end, the grid comes back to continue placing 2
at the beginning of the tracks.
In this tutorial, we explored CSS Grid: placing, spanning, and density.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!