June 18th, 2018

Introducing CSS Grid


CSS Grid

I'll be honest - most of the time when I write CSS I just hack away at things until they work. Building layouts in CSS never seemed intuitive to me. Other methods such as Androids XML layout system always seems more beginner friendly and powerful. Luckily creating web layouts in CSS gets easier every year. New features are added to CSS, and in the past year a new layout method called CSS Grid was added to the language specification. Now instead of using a library such as Bootstrap to manage page layouts, CSS has native support for easy grid layout management. I used CSS Grid in my React/ Webpack prototype back in March and applied it to every page on this website so far! I think CSS Grid is a major enhancement to the CSS specification, providing an easier entry point to new developers. This post looks into the basics of CSS Grid and acts as a stepping stone for further CSS discoveries down the line.

My software development journey began just two years ago in 2016 - so for the first 20 years of the CSS lifespan I was not around. Recently however I had to write some HTML and CSS for an email template. The HTML email I created is sent from this website when someone subscribes. When I first began development on the email I thought it would be an easy task - create a few <div> elements, write some CSS Grid styling, and call it a day. Little did I know that creating an HTML and CSS email is like building a website in 1999.

In order to get the email layout to work on all clients, the HTML had to be formatted using <table> elements1. None of the layout could be handled in CSS. The worst offender of all email clients was Outlook, which didn't even support the CSS width property2! You can checkout the gnarly HTML and CSS code for my email in all its beauty.

Luckily in recent years we didn't have to create layouts with HTML tables or define element widths as HTML attributes. We did it all in CSS! Before CSS Grid (and after the 90's) creating layouts consisted of either playing around with the CSS position and float declarations or giving up and using a library such as Bootstrap to handle layout creation for you.

When I started developing my first website SaintsXCTF in the fall of 2016, CSS Grid did not yet exist. At that point I was a beginner and didn't know bootstrap existed. If you look at most of the websites code all the layouts are created by floating <div> elements around the page and manipulating the position attribute. I won't go in detail of how to use this technique here, but it's safe to say it was challenging and confusing. Clearly the float attribute wasn't meant for designing layouts3.

Luckily CSS has evolved and introduced two new ways to create layouts natively - flexbox and grid. This post is about CSS Grid and the power it gives developers and designers.

CSS Grid

Grid is a two-dimensional layout system that uses rows and columns to format HTML4. CSS Grid replaces hacks such as CSS floats for creating layouts. It also is more powerful at creating grid layouts than Flexbox, which is a one-dimensional layout system. CSS Grid was first introduced in 2017 and is currently supported on most major browsers (as of June 2018).

To demonstrate how CSS grid works I designed a UI which displays different runs I went on this past week. Before using CSS Grid, here is what the UI looked like:

Now let's start working with CSS Grid. In order to create a grid, a container HTML element must be given the display: grid CSS definition. The columns in the grid are defined with grid-template-columns declarations and the rows are defined with grid-template-rows declarations.

The following .container class holds all the runs I went on:

<body> <div className="container"> ... </div> </body>
.container { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 10px; }

Two additional things to note about the .container class. You will notice that I use the fr unit, which represents a fraction of the space in a CSS Grid container. The grid-template-columns declaration specifies two columns with equal widths. The grid-gap declaration specifies the space between grid items.

Inside the container there are seven HTML <div> elements for the running logs.

<div class="container"> <div class="run run-6-17-0 run-6">...</div> <div class="run run-6-16-0 run-7">...</div> <div class="run run-6-15-2 run-5">...</div> <div class="run run-6-15-1 run-6">...</div> <div class="run run-6-15-0 run-5">...</div> <div class="run run-6-14-0 run-8">...</div> <div class="run run-6-13-0 run-4">...</div> </div>

In the initial CSS Grid layout I designed, the columns and rows are specified in each running log:

.run-6-17-0 { grid-column: 1; grid-row: 1; } .run-6-16-0 { grid-column: 2; grid-row: 1 / 3; } .run-6-15-2 { grid-column: 1; grid-row: 2; } .run-6-15-1 { grid-column: 1; grid-row: 3 / 5; } .run-6-15-0 { grid-column: 2; grid-row: 3; } .run-6-14-0 { grid-column: 1; grid-row: 5; } .run-6-13-0 { grid-column: 2; grid-row: 5; }

The result:

Notice that nothing is filling the grid space with column #2 and row #4. CSS Grid allows for easy declarations of whitespace in a layout.

One issue with the above code is it's quite lengthy for such a simple layout. To make a grid definition less verbose, the CSS properties grid-area and grid-template-areas are used. The following code creates the same exact layout as the previous one:

.container { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 10px; grid-template-areas: "a b" "c b" "d e" "d ." "f g"; } .run-6-17-0 { grid-area: a; } .run-6-16-0 { grid-area: b; } .run-6-15-2 { grid-area: c; } .run-6-15-1 { grid-area: d; } .run-6-15-0 { grid-area: e; } .run-6-14-0 { grid-area: f; } .run-6-13-0 { grid-area: g; }

grid-area gives each grid item a unique identifier and grid-template-areas defines the pattern for the grid. Note that the grid area with column #2 and row #4 is declared with the . token, denoting an empty grid space.

grid-template-columns and grid-template-rows are powerful because you can give unique identifiers to each line in between grid items. These unique identifiers are used within the grid items CSS declaration block for placement in the grid. Here are unique grid edge identifiers in action:

.container { display: grid; grid-template-columns: [left] 1fr [middle-start] 2fr [middle-end] 1fr [right]; grid-template-rows: [row-1] 1fr [row-2] 1fr [row-3] 1fr [bottom]; grid-gap: 10px; } .run-6-17-0 { /* Specify the items location within the grid */ grid-column-start: left; grid-column-end: middle-start; grid-row-start: row-1; grid-row-end: row-3; } .run-6-16-0 { /* Shorthand for specifying each column and rows start and end Goes in this order: row-start, column-start, row-end, column-end */ grid-area: row-3 / middle-start / bottom / middle-end; } .run-6-15-2 { grid-area: row-1 / middle-end / row-2 / right; } .run-6-15-1 { grid-area: row-1 / middle-start / row-3 / middle-end; } .run-6-15-0 { grid-area: row-3 / left / bottom / middle-start; } .run-6-14-0 { grid-area: row-2 / middle-end / row-3 / right; } .run-6-13-0 { grid-area: row-3 / middle-end / bottom / right; }

The result:

From all these examples, you may have noticed that each grid item stretches to fit its grid position. This behavior comes from each items align-self and justify-self properties, which default to stretch5. You can declare these properties with different values to change their behavior6 (I often use center which retains the shape of the original HTML element).

This concludes my brief introduction to CSS Grid. Hopefully you have seen why I am so excited about this new specification and the power it gives developers and designers to create layouts on the web. It has never been easier to design webpages with native CSS, and I am excited to continue growing my stylesheet knowledge.