loading...

CSS Grid Areas are amazing

kenbellows profile image Ken Bellows Updated on ・8 min read

When I first learned about CSS Grid Layout and the new powers it gave us as CSS developers, I was immediately excited. I was thrilled at the prospect of shedding all those layers of non-semantic container divs needed for a Bootstrap or Foundation grid, replacing them with purely semantic HTML documents and leaving the layout completely to CSS, as it always should have been.

But when I would talk to other developers who weren't as hyped about semantic markup, the response I often received was, "I already know how to do a grid system with , and I don't really want to learn a whole new thing right now... am I really going to gain something practical here, or will I just arrive back where I started, but in a different color car? What can I do with CSS Grid that I can't already do with a basic grid system?"

Today I want to answer that question with two words: Grid Areas.

Tracks and Lines

In CSS Grid Layout, a grid is made of tracks and lines. "Track" is the generic term for a row or column. As you might have guessed, "lines" are the boundaries between the tracks. We define our grids in terms of tracks with grid-template-rows and grid-template-columns, then we attach our grid items to our grid in terms of lines with grid-row and grid-column.

Grid tracks and lines

For many cases, perhaps most, tracks and lines are all you need to define your grid. Especially for smaller areas with dynamic content, like a grid of search results or a friends list, you can often just use grid-template-columns to define your columns, use grid-auto-rows to declare how tall new rows should be, and let CSS Grid's wonderful auto-placement behavior fill out your grid for you from there.

But sometimes things aren't that dynamic. Sometimes you have a predefined, fixed set of items to lay out in your grid, you know exactly where you want them to go, and you just want to hand the browser the correct answers, no auto-placement magic for you. This is very common when using a grid to lay out the top-level structure of a site: header goes here, navbar here, profile picture over there, content over here, done.

You can definitely still define everything by specifying your tracks fixing blocks to line numbers, and this is very common. For example, suppose you were coding up a simple user profile with four sections: a display name, an avatar, an "about" section, and a list of posts the user had made. You might do something like this:

<main>
  <h1 class="display-name">...</h1>
  <section class="avatar"><img src="..."></section>
  <section class="about">...</section>
  <section class="posts">...</section>
</main>
main {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
}
.display-name {
  grid-row: 1 / 2;
  grid-column: 3 / 6;
}
.avatar {
  grid-row: 1 / 3;
  grid-column: 1 / 3;
}
.about {
  grid-row: 3 / 4;
  grid-column: 1 / 3;
}
.posts {
  grid-row: 2 / 5;
  grid-column: 3 / 6;
}

The grid-template-columns rule for the grid container defines our column tracks, and the grid-row and grid-column rules for the grid items specifies which grid lines should be the boundary for each item.

And this definitely works. But there are some frustrations here:

  • Staring at a bunch of numbers can make your grid hard to visualize, and I often end up doing a lot of fiddling with those line numbers to get things looking right. This isn't an issue specific to CSS Grid, and tbh it's a lot easier than fiddling with padding and margins and float values and flex-grow, but it's still worth noting.
  • What if I want to add a new track or item later in between the existing tracks or items? I'll probably have to update a bunch of those line numbers up there. You could use the span keyword instead of a hard line number for the column- and row-end values, so you're specifying how many tracks to cover rather than which grid line to stop at, but that's a trade-off; sometimes it helps, sometimes it gets in the way.
  • There's a lot of repetition up there. Related to the previous point, if you just want to add a column on the left for, say, a sidebar, you'd have to find all instances of grid-row: 1 / ... and update each 1 to a 2. This gets worse in more complex layouts.
  • Responsive layouts with media-query breakpoints that shift things around can be a bit verbose and confusing, since you need to specify all these values for each breakpoint, which sort of compounds the issue of visualizing each different layout.

Thankfully, the writers of the CSS Grid spec have given us an amazing feature that helps to solve all of these problems: Grid Areas!

Areas

A grid area is a rectangular section of a grid, bounded on each side by a grid line (so, 4 grid lines, 2 horizontal and 2 vertical).

The simplest (and least interesting) way to use this feature is just as a shorthand for rows and columns on a grid item. Each of the sections in the example above could be simplified to a single grid-area rule:

/*
 grid-area: row-start / col-start / row-end / col-end;
*/

.about {
  grid-area: 3 / 1 / 5 / 3;
}

But that doesn't really solve any of the problems I listed; in fact, you might argue that it's worse, because it's a bit harder to read. (Which number represents grid-row-end again?)

So instead of that, instead of all these tracks and lines, let me show you a CSS Grid feature that absolutely blew my mind when I saw it: grid-template-areas!

main {
  display: grid;
  grid-template-areas: 
    "avatar avatar  name  name  name"
    "avatar avatar  posts posts posts"
    "about  about   posts posts posts"
    ".      .       posts posts posts"
  ;
}
.display-name {
  grid-area: name;
}
.avatar {
  grid-area: avatar;
}
.about {
  grid-area: about;
}
.posts {
  grid-area: posts;
}

Look at that.

Right?

Right???

Instead of defining rows and columns, we've laid out the whole grid visually with named grid areas, using what Rachel Andrew calls the "ASCII art" method of describing a grid. Each row is written as a string surrounded with double quotes ("..."), and each cell is given the name of the grid area it belongs to. If a cell doesn't need to belong to any area, just put a dot (or several dots, stylistic preference) in that spot. Cells are whitespace-separated, and excess whitespace is collapsed, which makes formatting the grid visually very easy.

Each grid area is defined by all the cells that bear its name. As you might guess, your areas must be rectangular and continuous; no tetris blocks or wormholes here.

Once you've got your grid areas defined, you can attach your grid items to them by setting an item's grid-area rule to the name of the area where you want it to go!

Note that there's no grid-template-columns or grid-template-rows here; by default, tracks are just inferred from the ASCII art! (How freaking cool is that??) With that said, you can still use those rules if you want to; this is often still necessary for sizing. You can also use the shorthand grid-template rule to define all three rules at once. In this shorthand, you can optionally give each row a height immediately following its description, then if you want column sizes you can add a slash after the final row and specify column sizes at the end:

grid-template:
  "avatar avatar  name  name  name"   2rem
  "avatar avatar  posts posts posts"
  "about  about   posts posts posts"  6rem
  "...... ......  posts posts posts"
  / 2fr    10px    3fr   1fr   5vw
;

IMHO, this is orders of magnitude more readable, visualizable, and ultimately maintainable for grid layouts with static items than long lists of explicit grid lines.

Responsiveness and Semantics

If I were asked what I think is the most exciting thing about CSS Grid, I would have to answer with this: the biggest benefit to the web that CSS Grid provides is that responsiveness is easy to accomplish without sacrificing semantics.

In the user profile example above, the careful reader may have noticed something odd: in the HTML, the order of the sections was:

  • display name
  • avatar
  • about
  • posts

But in the grid layout, the avatar came first, followed by the display name to the right, the about section below, and the posts in the bottom right. In addition, the posts section overlapped the avatar and the about section vertically.

The key point is this: the HTML tags are written in an order that makes sense semantically, but the grid layout makes sense visually. The HTML is written in the order that I would want a user to read the information. This is especially important for a user using assistive technology, like a screen reader: the fact that the CSS is moving things around on the page visually has no affect on the order of the elements, so the semantics is preserved.

That covers the semantics aspect, but what was that about responsiveness? Well, consider what would happen if the user were to narrow our profile layout to a mobile size, specifically a vertical orientation on a smaller screen. (Maybe you're already reading this on a mobile device, so you don't have to imagine!) It wouldn't look great. So let's add in a media query breakpoint at, say, 800px to rearrange our layout to reflect the section order listed above. You ready for this? Here's the code:

@media(max-width: 800px) {
  main {
    grid-template-areas:
        "name"
        "avatar"
        "about"
        "posts"
    ;
  }
}

Boom. That's it. That's all it takes.

It's just as visual as the first layout. And if you wanted a third layout, maybe one for super-wide screens that gets a little crazy and moves the avatar into a third column off to the left, that's just as easy:

@media(min-width: 1500px) {
  main {
    grid-template-areas:
        "avatar name  posts"
        "avatar about posts"
        ".      .     posts"
    ;
  }
}

Here's a demo that includes all three layouts above, but uses the grid shorthand rule, which resets values like track sizes. This avoids track sizes from the default layout being inherited in the other layouts, where they cause problems, without requiring me to override them explicitly in each breakpoint.

And in all three layouts, the HTML source order is never changed, so a user reading with a screen-reader, or for that matter a web crawler or screen-scraper, would still get the information on the page in the preferred semantic order.

Conclusion

I hope you're with me on this. I still hear pushback from web devs who have yet to seriously look into CSS Grid that they don't want to learn another new thing, that it's basically the same as the float- or Flexbox-based grid system they already know and use, or, most egregious of all, that it's just a return back to table-based layouts.

I hope I've shown in this article just how powerful CSS Grid is, both in terms of the layouts it can produce and in terms of just how easy it can be to create and maintain flexible, responsive, beautiful layouts, and all without sacrificing well-structured, slim, semantically pure HTML.

Once more I want to give huge props to Rachel Andrew. If you don't know her site gridbyexample.com, check it out. She has been personally advocating for CSS Grid for a decade, and she, along with Jen Simmons, has basically taught me Grid through her videos and tutorials. I'll give Rachel the last word:

Posted on by:

kenbellows profile

Ken Bellows

@kenbellows

Full-time web dev; JS lover since 2002; CSS fanatic. #CSSIsAwesome I try to stay up with new web platform features. Web feature you don't understand? Tell me! I'll write an article! He/him

Discussion

pic
Editor guide
 

Hi, this is great tutorial. Can you make navbar like dev.to?

 

Sure, you can add an element at the top like <nav id="navbar">, then add a navbar grid area and assign the element to that area. Bit as far as positioning content within the navbar, I actually think Flexbox might be the better choice for layout system, since it's a one-dimensional layout that needs to be flexible

 

You can show me tutorial? The dev.to is awesome navbar.

 

Great article about an excellent addition to CSS! I would add that this doesn't replace the functionality provided by flexbox as that is still a better solution in some cases. A dynamic length list of cards is one example that comes to mind.

 

Oh, definitely, Flexbox has plenty of advantages on many circumstances. I didn't mean for this article to be a proper intro to Grid, so I didn't bother with the usual "when to use it" discussion.

Actually though, regarding your example with cards, depending on what the cards look like I might still use Grid in order to keep the elements of the cards inline with each other, keep them the same height and all that. I'm actually currently working on a post about just that topic right now, and how display: contents and the upcoming subgrid addition factor into that kind of a layout.

 
 

OMG Ken, this CSS grid thing is awesome and so intuitive! Thanks for explaining it so well!

I also read this post by Rachel Andrew: You do not need a CSS Grid based Grid System.

Not writing rows and columns wrappers in the markup is liberating (especially because I might be able to stop littering the markup with those helpers only needed by the framework). It definitely helps accessibility too, as you mentioned.

I spent most of 2018 using Bulma (based on Flexbox) but this is much better.

It is finally time to start leaving CSS frameworks behind, or just use them for the components and not for layout :D

Vanilla CSS, vanilla JS, JAMstack websites... the web is getting simpler again ;-)

 

Yeah, definitely! I always hated digging through the layers of bootstrap containers to find the actual content; I'm thrilled to be able to write clean markup finally!

Another thing to look into with laying out components in a grid while maintaining semantics is display: contents, which I hope to write another article about soon.

 

I haven't tried named areas yet. Thanks for the enthusiasm. I feel hyped to try it

 

Any time! Post a link if you do something fun with it