There are various ways to build a responsive website layout. Choosing one can be confusing and implementing it can be complicated. The best solution is one that is quick, structured and comprehensive. Enter CSS Grid.
- Create a CSS Grid layout
- Identify CSS Grid properties
CSS Grid is a set of properties that allow us to rapidly build responsive layouts for websites. Similar to flexbox, you can use grid properties to build parts of an HTML page that grow and shrink dynamically, looking good on a variety of screen sizes.
However, where flexbox gives you very granular control over how individual elements stretch, shrink and behave in a flex container, grid places a greater emphasis on setting up the rules of the container itself, automatically handling the stretching and shrinking of elements by aligning them to rows and columns. Grid is designed for displaying content in two directions, whereas flexbox is designed for displaying in one direction.
We're going to dive straight in and set up a grid, then discuss the
properties involved. We're starting out with some basic code in our index.html
and index.css
files. Open up the index.html
in a browser tab, or if you're
using the Learn IDE, run httpserver
and navigate to the IP address provided.
Currently, in our HTML, we have one div with a class grid-container
, and
twelve divs inside of it.
If we look at the page in our browser, it is displaying the twelve divs,
stacked and filling the width of the screen. To turn this into a grid, we
need to apply some properties to the grid-container
class in our index.css
file. First, add the property display
, and set it to grid
. Save and
refresh index.html
in browser. Now, our twelve divs fill the page, evenly
dividing the height of our window. So, we see that using display: grid
alone takes all of an element's immediate children and evenly spaces them out,
effectively treating each div as a row in one column.
To give this grid a second dimension, we just need to add one property. Just
below display: grid
in the grid-container
class, add in:
grid-template: 1fr 1fr 1fr 1fr / 1fr 1fr 1fr;
Save and take a look at our page now. Instead of a just stack of twelve divs,
we now have a working grid! How is this working? In our grid-template
property, we're using a unique fraction unit, fr
, with a total of four
fractions, representing the number of rows in our grid, and then three more
fractions, representing the number of columns. We can set these to whatever we
would like. Let's swap them to see what happens: remove one 1fr
from the
first set and move it to the second. Now, our page is displaying three rows
and four columns!
In both examples, although we altered the grid structure, the divs inside automatically arranged to fit while remaining in order. They currently take up the whole page because both of these example grids have exactly twelve cells.
If you add extra fractions, say five 1fr
units for both rows and columns, the
twelve divs will be arranged into the first twelve available cells, leaving the
rest of the grid empty. If we do the opposite and remove our fraction units
until there are less than twelve cells defined in grid-template
, the
remaining divs will still be displayed within the grid, but will be appended
to the bottom.
We can also define some rows or columns as bigger than others. In
grid-template
, you can test this out by changing any of the 1fr
units to
2fr
. Now, the corresponding row or column will be twice as large as the
others.
Grids are often used to display an indeterminate amount of content - for
example, available products or a list of movies. In order to do this, when we
define the number of columns or rows in our grid-template
, we can assign
auto
. Set grid-template
to auto / 1fr 1fr 1fr
, save and check out the
page again.
This time, we're back to our original grid. However, we've defined the three columns, but have now set it so the browser decides how many rows are necessary. If you set just two columns, we will end up with six rows. Setting five columns will produce three rows, with three empty cells at the end.
Before we do anything else to our grid, let's talk about the specific properties CSS Grid provides.
Any time we want to implement a CSS grid, we must define it within the
display
property of the parent element. This causes the browser to interpret
all child elements of the parent to align to a grid. Child elements do not
need to have any height or width settings; they will stretch to fill the space
of their cells automatically.
The grid-template
property is actually shorthand for two other properties,
grid-template-columns
and grid-template-rows
. These can be defined
separately, and if only one is defined, the other will be set to the default
value, auto
. Because grid
is designed to display elements in a single
column, setting grid-template-columns
to auto
or not setting it at all will
always produce just one column, whereas setting grid-template-rows
to auto
will create as many rows as needed.
There are a number of units we can use in these template properties:
fr
- Represents a fraction unit. Usingfr
will set a cell's width or height based on the total number of fractions used. A setting of1fr 2fr 1fr 1fr
will result in each fraction being 20% of grid container, with the second cell being twice as large%
- You can use percentages for each row or column in a template. These will act similar tofr
units. It is possible to mix and match units in these templatespx
- Cells can be given a set width and height using the pixel unit. This can be helpful when you're creating more complex grids and want one row or column to stay the same sizeauto
- Theauto
value can be used as the default value, but can also be used to set specific columns and rows. This works well withpx
and%
units, so if we were to definegrid-template-columns
as50px auto 25%
, we would get a three column grid where the first column is always 50 pixels wide, the last column is always 25% of the total width of our container, and the middle column will fill the remaining space
In addition to these, the template properties have a unique setting, repeat
,
that makes definitions a little simpler. The repeat
setting takes in two
arguments: the first is the amount of rows or columns you want; the second is
the size of those columns, using the units above. So if we wanted to recreate
our original grid-template
using repeat
, it would look like:
grid-template: repeat(4, 1fr) / repeat(3, 1fr)
There is one more feature of the template properties worth exploring: when
defining a template of rows or columns, it is possible to give names to
specific lines in our grid. We do this by including these names in between
the unit values we're assigning, surrounded by square brackets, []
.
For example, if we wanted the first row of our grid to be where our 'header' will go, we might write the following:
grid-template-rows: [header-start] 1fr [header-end] 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
/* -or- */
grid-template: [header-start] 1fr [header-end] 1fr 1fr 1fr / 1fr 1fr 1fr;
The use of naming lines like this will become clearer later in this lesson.
If we need, we can also choose to define default sizes for our rows and grids
using grid-auto-columns
and grid-auto-rows
. These properties can take in
a length, or a unit such as fr
, and apply this as the default for all cells
in a grid. So, for instance, if we added grid-auto-rows: 50px;
to our
.grid-container
class, our grid will shrink a bit, as each row will now be
exactly 50 pixels tall.
There is one other property we can choose to set on the parent element:
grid-gap
. This property defines how much space is added in between cells. Go
back into our index.css
file and add grid-gap: 5px
to the grid-container
class. On our webpage, you'll see that each cell is now separated with
whitespace. Note that when using grid-gap
, the cells will shrink a little to still fit
in the container. The grid-gap
property can read pixel or percentage values.
So far, all of our properties have been assigned to the parent element of a
grid, but we can also add some properties to child elements to control how each
is arranged. To test this out, make a new CSS class called bigItem
with
the following settings:
.bigItem {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 3;
}
In our index.html
page, choose any one of our child elements and add bigItem
as a second class to the element (class="grid-item bigItem"
), save, and then
check out the page. Ah! Now we've got one big cell in the upper left corner
filled with just one div. All our other elements fill in the remaining space, in
order.
The start and end values here represent the lines between each grid item,
beginning from the far left and top of the container. So, the top line above
our first row equals 1, and that value increments for each additional line. A
single box in the upper left corner of our grid would extend from line 1 to
line 2 on both our rows and columns. Since we've set our .bigItem
to start
on 1 and end on 3 for rows and columns, the box extends and fills the four grid
cells in the upper left corner. Change our settings in .bigItem
to the
following, then refresh index.html
in your browser to see the change:
.bigItem {
grid-row-start: 2;
grid-row-end: 7;
grid-column-start: 2;
grid-column-end: 4;
}
Now, we've got a big central box with our remaining boxes fitting around the top, left and bottom. Defining a value greater than the number of columns or rows that are defined in our template will force the grid to extend out. This can cause an issue in our grid, if, for instance, we've only defined behavior for 4 rows and 3 columns.
Grid cells in the fifth, six and seventh rows default to the height of their
content. We can fix this by modifying our .grid-container
to include rules for
cells that have 'spilled over' into new rows.
If one of the start or end values is not entered, the size will always default
to one cell. So, given the settings above, if you took out grid-row-end: 7;
, a box would be created that starts on the second row and only extends down
to the third.
Setting grid-row-end
to 7
seems a little excessive, so let's set bigItem
to be a nice 2 x 2 cell:
.bigItem {
grid-row-start: 2;
grid-row-end: 4;
grid-column-start: 2;
grid-column-end: 4;
}
The grid-column-start
, grid-column-end
, grid-row-start
, and
grid-row-end
are frequently used in conjunction, so CSS has provided
shorthand alternatives: grid-column
and grid-row
. We can replace the
existing .bigItem
class with the following for the same effect:
.bigItem {
grid-row: 2 / 4;
grid-column: 2 / 4;
}
Both grid-column
and grid-row
take in two values, the start and end lines.
But wait! We can continue to reduce this. CSS provides another shorthand
option that replaces grid-column
and grid-row
: grid-area
. The grid-area
property takes in four values. In order, they are the start position for
row, the start position for column, the end position for row, and the end
position for column:
grid-area: <grid-row-start> / <grid-column-start> / <grid-row-end> / <grid-column-end>
We can then rewrite our .bigItem
class as one line:
.bigItem {
grid-area: 2 / 2 / 4 / 4;
}
Remember how it is possible to give names to lines using our grid-template
properties? This is where these names become useful. If we had names for the
beginning and end rows of a page footer, for instance, we could declare a
grid-area
for our footer as:
grid-area: footer-start / 1 / footer-end / 4
This would start our area wherever the line footer-start
is defined in our
row template, and end wherever footer-end
is defined. In a complex grid,
taking the time to name important lines in your layout makes it easier to
position grid elements to them without having to look up or count the number of
lines.
Grid has two additional properties that affect the contents of grid elements.
The justify-self
and align-self
properties define where, within a grid
cell, an element will be positioned. Using these properties will stop grid
from automatically expanding an element to fill the entire cell.
Let's add to our .bigItem
class to see this in action by changing the class
properties to the following:
.bigItem {
grid-area: 2 / 2 / 4 / 4;
height: 50%;
width: 50%;
justify-self: center;
}
Here, we've shrunk our element down to half the width and height of the
grid-area
we've defined. Using justify-self: center
, this smaller
box is now moved horizontally to the middle of the area. To center vertically,
we can add align-self: center
and the box will be perfectly centered
within the defined grid-area
. The justify-self
and align-self
properties
can be set to align to the start
or end
of an element, as well as stretch
to fit the space, or even align to the baseline
of inner text.
We can also choose to apply these justify and align rules to the entire grid
using two properties on the parent element: justify-items
and align-items
.
Just to recap, to get a grid up and running on a webpage, at minimum, you will
need one 'container' element. This element should display
set to grid
in its
styling.
Any child elements of this container will fit evenly into the rows of one
column. To make things a little more interesting, we need to use properties like
grid-template
on the container element, arranging content into however many
rows and columns we like.
To get fine tuned with specific content, we can apply styling to child elements, overriding template rules.
The tests in this lesson are in place to practice what we have discussed.
- In
index.css
, the.gridContainer
class should havedisplay
andgrid-template
properties correctly assigned - In
index.css
, there should be a.bigItem
class with agrid-area
property assigned - In
index.html
, thebigItem
class should be assigned to one of the divs
Run learn
to confirm you have correctly applied CSS Grid properties. If the
test pass, enter learn submit
. You'll then be prompted to move on!
CSS Grid allows us to set up a flexible grid-based page layout quickly and also gives us various properties to customize the grid. If you need an efficient way to build responsive websites, CSS Grid is a good modern tool.