An Exploration Into CSS Grid

I’ve relied on building webpage layouts using a variety of techniques – tables, floating divs, and flexbox. Not to mention CSS and JavaScript hacks to make older versions of Internet Explorer render box model layouts correctly. Lately I’ve been learning a lot about CSS Layout. It is the latest CSS technology for building layouts optimized for the web and I’m amazed at what it can do. Flexbox is great, but it has its limitations. It only allows you to build one-dimensional layouts. CSS Grid, however, enables you to build layouts in two dimensions simultaneously. Now that CSS Grid comes shipped with browsers such as Safari, Chrome, Opera, Firefox, and Edge, you can start using this new layout system in your projects today. This article is an exploration into CSS Grid, the latest in CSS technology, which I think will revolutionize the way designers and developers build interfaces for the web.

A Simple Grid Layout

Let’s build a simple layout using CSS Grid. First, define the grid container. Set an element’s display value to “grid”.

#grid {
   display: grid;
}

Grid items are the children of the grid. The items of the grid we define here are the header, left navigation, content, and footer. Give each of them a name, or a custom identifier, by assigning it to their grid-area property.

.header {
   grid-area: header;
}

.left-nav {
   grid-area: left-nav;
}

.content {
   grid-area: content;
}

.footer {
   grid-area: footer;
}

You define the width of columns by setting sizing values to the grid-template-columns property. As for the height of rows, you set the sizing values to the grid-template-rows property. The grid’s columns and rows are known as Grid Tracks.

grid-template-rows: 100px auto 25%;
grid-template-columns: 200px auto;

Set the values for the grid-template-areas property. In this property, each grid item’s name is arranged in an order in which you want them to be displayed on the grid. A row represents a string set. For example, “header header” is a row. And so is “left-nav content.” The columns are represented by names, separated by a space. Note that “header” is shown twice since it takes up both columns in that row.

grid-template-areas: "header header"
                     "left-nav content"
                     "footer footer";

Here’s the HTML. Each nested <div>represents a grid item.

<div class="header">header</div>
<div class="left-nav">left-nav</div>
<div class="content">content</div>
<div class="footer">footer</div>

The result:

Useful Grid Layout Features

As you can see, it didn’t take much effort to get a simple grid layout prototype up and running. However, Grid Layout has much more to offer. Let’s utilize other Grid Layout features to customize our grid even further.

Track Sizing Values

When you define the track sizing of a grid, the track listing in the grid-template-rows and grid-template-columns can also accept track size values other than length, auto, and percentage. Consider the following example:

grid-template-rows: 100px 2fr 1fr;
grid-template-columns: minmax(200px, 500px) auto;

Here, we can use a track size value returned by the minmax() function (exclusive to Grid Layout) and a fr unit value. They both are used to create a responsive grid.

The minmax() function takes two parameters: a minimum value and a maximum value. In our example above, the minimum is 200px and the maximum is 500px. Resizing the viewport results in function returning column width values between the minimum and maximum values.

The fr is known as a “fractional unit.” If a grid item has a track size value for either a row or column of one fractional unit, it takes up a fraction of available grid container space. In the example above, the remainder of the grid’s height (the height of the grid minus the height of row 1), is distributed between row 2 and row 3. Two-thirds (2fr) of the height goes to row 2 and one-third (1fr) of the height goes to row 3.

Responsive grid

For a responsive grid, modify the following grid container properties per media query: grid-template-rows, grid-template-columns, and grid-template-areas.

/* 321px and up */
@media(min-width: 321px) {
   #grid {
      grid-template-rows: 100px 2fr 1fr;
      grid-template-columns: 200px auto;
      grid-template-areas: "header header"
                           "left-nav content"
                           "footer footer";
   }
}

/* 320px and below */
@media(max-width: 320px) {
   #grid {
      grid-template-rows: 100px 1fr 3fr 100px;
      grid-template-columns: 100%;
      grid-template-areas: "header"
                           "left-nav"
                           "content"
                           "footer";
   }
}

Notice how the grid-template-areas value is set up for the 320px and below media query. Each
named area forms one column, since this view is for mobile phone devices.

Named Lines

Although you can reference grid lines by numerical index, Grid Layout allows you to create custom names for grid lines. This feature helps identify, maintain, and provide a meaningful reference to grid lines and areas in your stylesheet. Use the named lines as a value in the grid-template-rows property and grid-template-columns property of a grid. Provide any name you choose for a line, but ‘span’. You surround the custom line name in brackets. The same line can also have multiple names. For example, you may want to refer to a line that signifies the end of a column and the start of an adjacent column. However, I found that multiple names can be overkill, so I like the idea of having one name per line.

#grid {

	grid-template-rows: [row1-start] 100px [row2-start] 2fr [row3-start] 1fr [row3-end];
	grid-template-columns: [col1-start] minmax(200px, 500px) [col2-start] auto [col2-end];
}

Interestingly, you can have multiple lines with the same name. But how do you reference a specific line if there are lines sharing the same name? Let’s see an example of how to accomplish this. In this example, we will need to pinpoint the correct line names to place our grid items on specific locations on the grid.

Let’s use the repeat() function to create a grid of 3 rows and 2 columns:

#grid {

	display: grid;
	grid-template-rows: repeat(3, [row-start] 1fr [row-end]);
	grid-template-columns: repeat(2, [col-start] 1fr [col-end]);
}

To place each item on the grid, we set the values for their grid-row property and grid-column property. The values consists of the line name and a number. The number corresponds to the row or column number of the grid:

.header {

	grid-row: row-start 1/row-end 1;
	grid-column: col-start 1/col-end 2;
}

.left-nav {

	grid-row: row-start 2/row-end 2;
	grid-column: col-start 1/col-end 1;
}

.content {

	grid-row: row-start 2/row-end 2;
	grid-column: col-start 2/col-end 2;
}

.footer {

	grid-row: row-start 3/row-end 3;
	grid-column: col-start 1/col-end 2;
}

The span keyword

You can place an item on the grid by number. The number references the grid’s column or row number. Then, you can use the span keyword to span across adjacent rows or columns. The item can also span into an already defined area that occupies that space on the grid. For example, if we span the left-nav from row two into row 3, it is essentially spanning itself into the area defined as the footer. To visually see the overlapping areas, just set the z-index property for both items.

.left-nav {

    grid-row: 2/span 3;
    grid-column: 1;
    z-index: 2;
}

.footer {

    grid-row: 3;
    grid-column: 1/span 2;
    z-index: 1;
}

Conclusion

Creating a simple layout and getting started with CSS Grid couldn’t be any easier. You have full control of the position, size, alignment, and layering (via z-index) of the items you place on the grid. However, the specification comes with so many more features I didn’t go over in this article (I’ll save them for future articles). Until then, my Grid exploration continues. I hope this article was inspiration enough for you to go and explore for yourself, the latest in CSS technology, that will revolutionize the way designers and developers build for the web.

Featured photo by  

unsplash-logoMarkus Spiske