CSS Grid!
CSS is the most modern way of creating web page layouts, however it’s important to note that CSS Grid isn’t necessarily meant to replace Flexbox….they can in fact work together on the same web-page…. the key thing to remember is that Flexbox is designed to work with one-dimensional layouts, but CSS grid is designed to work with two-dimensional layouts.
Whereas Flex uses Flex containers and Flex items (parent element and child elements) instead CSS Grid uses Grid Containers and Grid items.
We declare CSS grid containers with display: grid
Grid containers can be thought of in two dimensions….. columns and rows. You can define a Grid container with both a number of columns and rows, and then the Grid items (child elements) will be positioned based on how you defined these columns and rows.
To demonstrate this, let’s first set our HTML and CSS to the same boilerplate we used for the previous posting….
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- link to the CSS file -->
<link rel="stylesheet" href="styles.css">
<title>Mastering CSS Grid!</title>
</head>
<body>
<div class="container">
<div class="el el--1">HTML</div>
<div class="el el--2">and</div>
<div class="el el--3">CSS</div>
<div class="el el--4">is</div>
<div class="el el--5">cool</div>
<div class="el el--6">when</div>
<div class="el el--7">using</div>
<div class="el el--8">CSS Grid</div>
</div>
</body>
</html>
CSS
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
}
.el--1 {
background-color: blueviolet;
}
.el--2 {
background-color: orangered;
}
.el--3 {
background-color: green;
height: 150px;
}
.el--4 {
background-color: goldenrod;
}
.el--5 {
background-color: palevioletred;
}
.el--6 {
background-color: steelblue;
}
.el--7 {
background-color: yellow;
}
.el--8 {
background-color: crimson;
}
which gives us this….
Let’s now apply the CSS Grid to what will be the Grid Container, which in this case will be the “container” div.
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
}
Now unlike flexbox, this doesn’t appear to change anything yet. With display: flex, the flex items would’ve been placed side by side in the container horizontally, but declaring display: grid doesn’t do this.
For CSS grid, we actually have to declare some more information. Let’s define three columns with specific pixel widths per column using grid-template-columns
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: 300px 450px 600px;
}
this is what we get….
CSS grid then places the first Grid Item in the first column, the second Grid item in the second column, and the third grid item in the third column. Now because we’ve specified three columns, what happens is that when we get to the Fourth Grid item, CSS grid starts again, putting the fourth item in the first column, the fifth item in the second column and the sixth item in the third column, and again, start back on the first column with the seventh item.
If we switch this just to two columns, you can see the effect this has:
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: 300px 600px;
}
Now whilst we could define a column (or row) based on a pixel amount, we want to take advantage of these columns (or rows) resizing dynamically. So for example, how could we make these two columns fill the entire container space without specifying a pixel amount?
Fractions!
We can use fractions to allow the columns to take up all the space. If we currently have two columns, then we could say that we have two fractions…. if we want to make the columns equally wide, then we apply 1fr to the first column and 1fr to the second column, like this:
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: 1fr 1fr;
}
which gives us this:
alternatively we could make the first column occupy 3/4 of the width, and the second column occupy 1/4 of the width, so we could do the following:
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: 3fr 1fr;
}
which gives us this….
Note that for the second row, the height of that row is based on the height we set for the green element of 150px (hence why that row is taller)…for all other rows, they are set automatically based on the content of the element.
You can also mix and match fixed values with fr’s.
For example….
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: 1fr 100px 3fr 500px;
}
which gives us this….
What’s interesting here is if we resize the page, the specified pixel columsn stay the same width, but the fr columns adjust accordingly….this is what happens when I make the browser narrower….
So the first and third columns shrank in width, but the second and fourth columns maintained their specified width.
You can also use auto, which will take up any available space. So for example, you could set all column widths to auto, and they will all resize automatically, based on the page width, however you’ll notice that not all the columns are of equal width….
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: auto auto auto auto;
}
here is what you’d see….
You can see that the fourth column is definitely the widest…. also, the first column is slightly wider than the second and third column. This is because of the content inside the elements. It’s more difficult to see at full page width, but if I narrow down the size of the page, you can see why this is…
The very last CSS Grid box has the widest content, followed by the first box. So CSS grid is taking into account the width of the parent element, and then dividing up the columns automatically based on the required width of the columns, and right now, the last box needs the widest amount of space, so in terms of a percentage of overall width, it takes up the most space.
Interestingly though, if I continue to make the page even narrower, then the last box text conent wraps to a new line, and at this point it doesn’t require the biggest percentage of width, and therefore is no longer the widest column. In fact, it suddenly becomes the narrowest column!
we can show that all the columns would have equal width, if we put the same width content in all the boxes except one….
Ok so how could we make all the child elements line up horizotnally, similar to the effect of flexbox?
We simply just create a single column…..
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: auto auto auto auto auto auto auto auto;
}
which gives us this….
Fortunately there is a shorthand way of writing something like this, which is to use the “repeat” option..
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(8, auto);
}
Or if you really did want all 8 columns to be of equal width, then you’d set them each to 1fr
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(8, 1fr);
}
Creating gaps
Similarly to Flexbox, with CSS Grids, you can specify gaps rather than using margins, only with CSS Grids you can specify gaps both horizontally and vertically using column-gap and row-gap
So for example, if I set this back to four columns, and set all columns to 200px wide, we’d get this….
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(4, 200px);
}
and now we can apply a 50px gap between all the columns with column-gap
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(4, 200px);
column-gap: 50px;
}
Let’s now create a 20px gap between the rows….
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(4, 200px);
column-gap: 50px;
row-gap: 20px;
}
What about if we wanted to make the second row the same height as the first row? We could so this by specifying both rows as 1fr, which means it will ensure both rows are the same height…
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(4, 200px);
column-gap: 50px;
row-gap: 20px;
grid-template-rows: repeat(2, 1fr);
}
which gives us this….
the height is of course based on the green element which has a specified height of 150px, but if we remove that, then both rows would only have a height necessary for the conent to fit. To show this we’ll remove the fixed height of 150px for the green element temporarily….
.el--3 {
background-color: green;
/* height: 150px; */
}
Spacing Grid items evenly
For Flexbox, we simply used justify-content: space-between…
We can do the same thing for CSS Grid items…
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(4, 1fr);
column-gap: 50px;
row-gap: 20px;
grid-template-rows: repeat(2, 1fr);
justify-content: space-between;
}
which gives us this….
To do this vertically, you would use align-content
This will be easier to see if I give the container a fixed height of say 500px, but set the row height to 100px
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(4, 1fr);
column-gap: 50px;
row-gap: 20px;
grid-template-rows: repeat(2, 100px);
justify-content: space-between;
height: 500px;
}
this creates this…
now I can use align-content:space-between for the rows
.container {
font-family: sans-serif;
background-color: #ddd;
font-size: 40px;
margin: 40px;
display:grid;
grid-template-columns: repeat(4, 1fr);
column-gap: 50px;
row-gap: 20px;
grid-template-rows: repeat(2, 100px);
justify-content: space-between;
height: 500px;
align-content: space-between;
}
Moving elements to occupy other grid positions
One of the great things about CSS grid is that you can move elements to occupy other grid positions, and can even make the re-positioned element take up more than one grid space.
The broswer inspector lets us look at the grid reference numbers…
So for example, if I wanted to move the yellow element to the first position, I would reference the first column and the first row as my start position, and the second column and second row as my end position….
.el--7 {
background-color: yellow;
grid-column: 1 / 2;
grid-row: 1 / 2;
}
which gives us this….
Note that if you’re only planning to span one cell, then you can also write it shorthand without an end value like this:
.el--7 {
background-color: yellow;
grid-column: 1;
grid-row: 1;
}
you could set a bigger end number to make the items take up more than one cell. For example…
.el--7 {
background-color: yellow;
grid-column: 1 / 4;
grid-row: 1 / 2;
}
which creates this….
rather than supply an end number, you can also just state how many columns or row you wish to span. So for example, the following creates the exact same thing….
.el--7 {
background-color: yellow;
grid-column: 1 / span 3;
grid-row: 1 / span 1;
}
Spanning the entire column or row
What if you wanted the Flex item to span the entire column or row, but didn’t know how many columns/rows you had? Well you can simply specify 1 as the start, and -1 as the end.
.el--7 {
background-color: yellow;
grid-column: 1 / -1;
grid-row: 1 / span 1;
}
This is because the CSS Grid has left to right and top to bottom values going from 1,2,3,4,5 etc.
But it also has RIGHT to LEFT and BOTTOM to TOP values of -1, -2, -3, -4 -5, etc.
So we know that the end column or row will always be -1, and the second-to last column or row will always be -2, etc.
Moving individual items
Similarly to flexbox, you can also align individual items using justify-self and align-self
So for example, lets say I want the purple box to move up to the top…
.el--7 {
background-color: yellow;
grid-column: 1 / -1;
grid-row: 1;
}