Table of Contents
Have you heard about CSS grid? This is currently a very popular topics on web design scene, probably one of the most popular. It is also one of the most searched CSS features on CanIUse website. It is not a surprise. It is safe to say that CSS grid has the potential to cause a revolution in web design. In this tutorial, you will learn how to use this promising CSS feature to build your own simple layout. The future of web design arrived today. Let’s take a look at it!
Demo on Codepen.
Briefing
Before we get any further, let’s talk about the environment for this tutorial. Or, what will you need to get the code running? This tutorial will not use any external framework or resources. Well, except one. This will be font awesome. I used this font in order to show the icons for browser support and the heart icon in the footer. There is no other use of this font. So, you don’t have to use this font unless you want to use these (or other) icons.
Also I didn’t use any CSS stylesheet for resetting / normalizing CSS styles. This means that the only styles used are the styles you can see. The next thing are vendor prefixes. As you will notice, the CSS code contain no vendor prefixes. The reason is simple. Codepen allows to choose one of two plugins that take care about this. Then, code is prefixed automatically on the background. These plugins are autoprefixer and prefixfree.
You can see this option if you click on “Settings” button, in the Codepen header, and navigate to CSS tab. You may need to switch to “Editor view” via “Change view” button. Okay, what if you want to see the CSS code with all prefixes? Then, in “Editor view”, click on the button with down arrow (or angle) and click on “View Compiled CSS”. This will show you the Sass code compiled into CSS with all prefixes.
Lastly, let’s quickly address current support for CSS grid. Or, what browser will you need to make the code work? CSS grid will work, more or less, on IE +11, Edge +14, Chrome +57, Firefox +52, Opera +44 and Safari +10.1. Opera 43 and Chrome 49-56 require enabling “experimental Web Platform features” flag in chrome://flags. In case of Firefox 51, use “layout.css.grid.enabled” flag.
HTML
The first part of this CSS grid tutorial is about setting up the HTML structure. This structure will contain a number of blocks – header, sidebar, main block and footer. These blocks will be wrapped inside div element with class “grid”. This will be the first element using CSS grid. Header will contain only h1 tag with simple text. Sidebar (aside) will contain h2 tag with list containing six links. The main block will contain eight cards (article). This will be the second element using CSS grid.
We will use CSS grid for main block to distribute the cards evenly on different screen resolutions. Footer will contain list with six items showing current browser support for CSS properties related to CSS grid. And, footer will contain a short note. We can call this note epitaph. Below is the whole HTML structure we will need for this tutorial.
HTML:
<!-- Grid container and main wrapper --> <div class="grid"> <!-- Header --> <header> <h1>Introduction to CSS grid</h1> </header><!-- .end Header --> <!-- Sidebar --> <aside> <h2>Navigation:</h2> <nav> <ul class="nav"> <li><a href="#">Nav Link 1</a></li> <hr /> <li><a href="#">Nav Link 2</a></li> <hr /> <li><a href="#">Nav Link 3</a></li> <hr /> <li><a href="#">Nav Link 4</a></li> <hr /> <li><a href="#">Nav Link 5</a></li> <hr /> <li><a href="#">Nav Link 6</a></li> </ul> </nav> </aside><!-- .end Sidebar --> <!-- Main content --> <main> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> <article class="card"> <h1 class="card__heading">Heading</h1> <p class="card__excerpt"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ex quidem quis adipisci accusantium laboriosam quae voluptatem, nesciunt dolorum labore ipsa? </p> <a href="#"><strong><small>read more »</small></strong></a> </article> </main><!-- .end Main content --> <!-- Footer --> <footer> <ul class="footer-support"> <li> <span> <i class="fa fa-chrome"></i> <span class="browser-version">57</span> </span> </li> <li> <span> <i class="fa fa-edge"></i> <span class="browser-version">14</span> </span> </li> <li> <span> <i class="fa fa-firefox"></i> <span class="browser-version">52</span> </span> </li> <li> <span> <i class="fa fa-internet-explorer"></i> <span class="browser-version">11</span> </span> </li> <li> <span> <i class="fa fa-opera"></i> <span class="browser-version">43</span> </span> </li> <li> <span> <i class="fa fa-safari"></i> <span class="browser-version">10.1</span> </span> </li> </ul> <small class="epitaph"> Built with <i class="fa fa-heart"></i> by <a href="www.alexdevero.com"><u>Alex Devero</u></a> </small> </footer><!-- .end Footer --> </div><!-- .end Grid container and main wrapper -->
CSS (Sass)
Like in case of flexbox, there are many ways to approach this subject. There is the hard and the easy way. You can use flexbox with just a few lines of code. If you want to master it, you have to learn about a lot of CSS properties. The same is true about CSS grid. Grid, too, comes with amount of new CSS properties and values. My goal is to show you the minimum effective dose, not to overwhelm you. I want to help you get started. So, I will do my best to keep this tutorial simple.
We will be using a small number of CSS grid-related properties. These properties are grid-template-areas, grid-template-columns, grid-template-rows, grid-row-gap, grid-column-gap and display with “grid” as value. You can find the rest of all properties and values in this Complete Guide to Grid published on CSS Tricks. This guide also explains important terminology. So, if you find yourself in doubt, check this guide. You will probably find a solution. Now, back to the tutorial.
Sass workflow and resets
The first thing we will do is creating a few variables and one function to make our work easier and faster. If you are not familiar with Sass preprocessor, I highly recommend reading The Beginner’s Guide to Learn Sass Part 1, Part 2 and Part 3. This mini series will take you from basic of Sass to the most advanced topics and some tips & tricks. You will learn all you need to start using Sass at full-speed. Next, we will reset and add custom styles for html, body, a and ul elements.
Sass:
// Sass function for converting pixels to rems @function remy($value) { @return ($value / 16px) * 1rem; } // Sass variables $spacing: remy(16px); $spacing-big: remy(32px); $spacing-small: remy(8px); //- Basic resets -// html { font-size: 100%; } body { margin: 0; font: 16px / 1.414 Verdana, Arial, sans-serif; background-color: #f4f5f7; } a { $color: #212121; text-decoration: none; color: $color; transition: color .25s; &:focus, &:hover { color: lighten($color, 25%); } } ul { padding: 0; margin: 0; display: flex; list-style-type: none; }
Enter the grid
That was easy intro. Now, let’s dive right into the CSS grid. We will use our grid class to apply grid styles to the div that wraps the whole page. First, we need to set display property to “grid”. Then, we will set grid-template-areas property to “’header’ ‘sidebar’ ‘main’ ‘footer’”. Each row contains element(s) inside the quotes. So, first row contains ‘header’, second ‘sidebar’, fourth ‘main’ and fifth ‘footer.’ This basically means that our grid will contain four rows stacked on top of each other.
Next, we will use grid-template-columns property to specify how much space of the grid will each area in the row (think element like ‘header’) take. We want to keep it full-width so we will use “1fr” which stands for 1 fraction. After that, we will use grid-template-rows with minmax() CSS function to make sure the footer will always stick to the bottom. This will let the center of the grid remain flexbile and expand as screen allows while keeping header and footer at the same height.
In order to make this work, we will also need to set height to “100vh” (viewport height). Next are some styles for reducing the max-width of the grid and centering it. After that, we will use media query to target screen with higher than 768 pixels. When this happens, we will restructure the grid. From that moment, first row will still contain only ‘header’, second will contain ‘sidebar main’ and third will contain ‘footer’. We will also set grid-template-columns will to 1fr 4fr.
This means that the first area (element) inside the quotes (grid-template-areas) will cover 1 fraction of the grid while the second will cover 4 fractions. In other words, we will split the grid into two columns (fractions). One will take 1/5 (1 fraction) of the space and the second 4/5 (4 fractions). Also, the duplicate header and footer areas (‘header header’ ‘sidebar main’ ‘footer footer’) in grid-template-areas is not a mistake.
We are saying that we want these areas to fill both columns of the specific row. Or, this row should contain only header / footer and it should be full-width. Otherwise, header and footer would cover only one fraction or column. What if you want to split the grid into three columns?
Then, you can set grid-template-columns to “1fr 3fr 1fr” (or any other fractions of the space). And, you will set grid-template-areas to “’header header header’ ‘sidebar-left main sidebar-right’ ‘footer footer footer’”. Again, header and footer will be full-width. Sidebar-left and sidebar-right will both take 1/4 of the space and main will take 3/4. If you want header or footer to fill only 2 columns you will use “’header header’ ‘sidebar-left main sidebar-right’ ‘footer footer’”.
I know that grid-template-areas and grid-template-columns can be a bit tricky to understand. The best way to understand it is by trying different numbers of fractions along with adding / removing areas to see what will happen. Remember that you are dividing the grid into fractions. One more example. Let’s say you want to divide it into two halves. Then, set the grid-template-columns to “1fr 1fr”. This means that first column with take 1/2 of the grid and second will take 1/2 as well.
Sass:
//- Set the grid layout -// .grid { display: grid; grid-template-areas: 'header' 'sidebar' 'main' 'footer'; grid-template-columns: 1fr; grid-template-rows: minmax(min-content, max-content) auto minmax(min-content, max-content); margin-right: auto; margin-left: auto; max-width: remy(1170px); min-height: 100vh; @media screen and (min-width: 768px) { grid-template-areas: 'header header' 'sidebar main' 'footer footer'; grid-template-columns: 1fr 4fr; } }
Defining template areas
By now, you may wonder, how the grid knows what area relates to which HTML element? Great question! The truth is that you have to specify it explicitly. If you want to use some element with grid-template-areas as an area, you need to target this element and use grid-area CSS property set to some name for that area. Don’t use spaces or quotes. You can use camelCase or dashes. For example, grid-area: header, grid-area: footer, grid-area: sidebar-left or grid-area: sidebarRight.
In our example, we used header, main, sidebar and footer as areas. This means that we need to use grid-area for header, main, aside and footer with proper values.
Sass:
//- Define template areas -// header { grid-area: header; } main { grid-area: main; } aside { grid-area: sidebar; } footer { grid-area: footer; }
Creating second grid
There are a lot of styles to make the example for this tutorial look good. However, these styles are not necessary for learning about CSS grid. And, going over all the styles would take a lot of time. I will skip this code and stick only to what is directly related to CSS grid. Don’t worry, I will include the whole Sass code in the end. Now, let’s move to the second and last appearance of CSS grid in this tutorial. We can use grid to take our eight cards in the main area and create simple grid layout.
First, we will need to select the main element and set its display property to “grid”. We will use mobile-first approach. This means that we will use grid-template-columns and set it to “100%”. Meaning, the grid should contain one full-width column. Next, we will use grid-row-gap and to create some spacing between rows. $spacing-big variable is equal to 32px. This will be enough. After that, we can move beyond mobile screens.
We will create first media query targeting screens with width of 480px and wider. Inside this media query we will change set grid-template-columns to “auto auto” (without quotes). This means that we want two columns with equal widths in each row. We will also use grid-column-gap property and set it to $spacing variable (16px). This will create 16px wide gap between columns. Another media query will target screens 992 and wider.
Inside this media query, we will set grid-template-columns to “auto auto auto”, again without quotes. This will create rows with three cards with equal widths in each. Finally, let’s create one more media query for screen widths of 1200px and wider. This media query will change the value of grid-template-columns to “auto auto auto auto”. Yes, you guessed it. We want to have four cards with the same width in each row.
Sass:
main { display: grid; grid-template-columns: 100%; grid-row-gap: $spacing-big; @media screen and (min-width: 480px) { grid-template-columns: auto auto;// 2 cards per line with equal widths grid-column-gap: $spacing; } @media screen and (min-width: 992px) { grid-template-columns: auto auto auto;// 3 cards per line with equal widths } @media screen and (min-width: 1200px) { grid-template-columns: auto auto auto auto;// 4 cards per line with equal widths } }
Putting it all together
As I promised, here is the whole code for this tutorial. Keep in mind that it contains a lot of CSS used only for additional styling. If you want to replicate the design in this tutorial completely, use the code below. If you only want to practice with grid you can use only the snippets we discussed on the lines above. Also, if you want to see compiled CSS with all prefixes, take a look at the demo on Codepen in “Editor view” and choose “View compiled CSS” on CSS editor tab.
Sass:
// Sass function for converting pixels to rems @function remy($value) { @return ($value / 16px) * 1rem; } // Sass variables $spacing: remy(16px); $spacing-big: remy(32px); $spacing-small: remy(8px); //- Basic resets -// html { font-size: 100%; } body { margin: 0; font: 16px / 1.414 Verdana, Arial, sans-serif; background-color: #f4f5f7; } a { $color: #212121; text-decoration: none; color: $color; transition: color .25s; &:focus, &:hover { color: lighten($color, 25%); } } ul { padding: 0; margin: 0; display: flex; list-style-type: none; } //- Set the grid layout -// .grid { display: grid; grid-template-areas: 'header' 'sidebar' 'main' 'footer'; grid-template-columns: 1fr; grid-template-rows: minmax(min-content, max-content) auto minmax(min-content, max-content); margin-right: auto; margin-left: auto; max-width: remy(1170px); min-height: 100vh; @media screen and (min-width: 768px) { grid-template-areas: 'header header' 'sidebar main' 'footer footer'; grid-template-columns: 1fr 4fr; } } //- Define template areas -// header { grid-area: header; } main { grid-area: main; } aside { grid-area: sidebar; } footer { grid-area: footer; } //- Header -// header { padding-top: $spacing; padding-bottom: $spacing; margin-bottom: $spacing; background-color: #fff; box-shadow: 0px 2px 40px 0px rgba(0, 0, 0, 0.08); h1 { margin-top: 0; margin-bottom: 0; font-size: 18px; font-weight: 700; text-align: center; text-transform: uppercase; } } //- Navigation -// aside { padding: $spacing; background-color: #fff; @media screen and (max-width: 767px) { padding-bottom: $spacing; margin-bottom: $spacing; } @media screen and (min-width: 768px) { margin-right: $spacing; } h2 { @media screen and (max-width: 767px) { display: none; } margin-bottom: $spacing-small; font-size: 14px; } } .nav { flex-direction: row; justify-content: center; a { font-size: remy(12px); } @media screen and (max-width: 767px) { hr { display: none; } li + li { margin-left: $spacing; } } @media screen and (min-width: 768px) { flex-direction: column; justify-content: flex-start; hr { margin-top: $spacing-small; margin-bottom: $spacing-small; margin-left: 0; width: remy(36px); height: 1px; background: #eee; border: 0; } li + li { margin-top: $spacing-small; } } } //- Main area -// main { display: grid; grid-template-columns: 100%; grid-row-gap: $spacing-big; @media screen and (min-width: 480px) { grid-template-columns: auto auto; // 2 cards per line with equal widths grid-column-gap: $spacing; } @media screen and (min-width: 992px) { grid-template-columns: auto auto auto; // 3 cards per line with equal widths } @media screen and (min-width: 1200px) { grid-template-columns: auto auto auto auto; // 4 cards per line with equal widths } } //- Cards -// .card { display: flex; flex-direction: column; padding: $spacing; background-color: #fff; box-shadow: 0 20px 20px rgba(0, 0, 0, .08); transition: all 250ms cubic-bezier(.02, .01, .47, 1); &:focus, &:hover { box-shadow: 0 30px 30px rgba(0, 0, 0, .16); transform: translate(0, -10px); } a { margin-top: auto;// Push link to the bottom of the card } } .card__heading { margin-top: 0; font-size: remy(18px); } .card__excerpt { font-size: remy(14px); } //- Footer -// footer { margin-top: remy(24px); background-color: #fff; } .footer-support { padding-top: $spacing-big; padding-bottom: $spacing; display: flex; justify-content: center; li + li { margin-left: $spacing; } .browser-version { font-size: remy(14px); } } .epitaph { padding-top: $spacing-small; padding-bottom: $spacing; display: block; text-align: center; } .fa-heart { color: #e74c3c; }
Closing thoughts on CSS grid
Congratulations! You’ve just made your first layout using CSS grid! I hope that it was easy for you to follow this tutorial and learn about this CSS feature. Are you still trying to wrap your head around some things we discussed? Use the code I wrote for this tutorial, or fork my pen on Codepen, and play with it. If you are not sure how some property works, play with it and try using different values. Also, take a look at that guide published on CSS tricks. Remember, it all comes to practice.
If you liked this article, please subscribe so you don't miss any future post.
If you'd like to support me and this blog, you can become a patron, or you can buy me a coffee 🙂