Multiple Layouts Made Easy with CSS Grid

The software we develop at Revalize serves a wide range of customers from a wide range of industries. Designing for so many different types of users can be daunting—what works for a group of users from one company won’t necessarily work for another. The most challenging problem to solve in our designs is the application’s various layout requirements. Thanks to CSS Grid Layout, creating multiple layouts from a single source of markup has been made, dare I say, trivial.

N.B.: This post references CSS Grid Layout, but is not intended to be an introductory tutorial to the technology. If you’re new to CSS Grid Layout, consider the following resources before reading this article:

In this post:

The old days

Let’s focus on the dashboard for a fictitious application, Super App 3000®. Prior to CSS Grid Layout, you might have reached for Perfect Grid System™ to handle your layouts. Such a system typically results in markup that looks like this:

<main>
  <div class="row">
    <div id="module_1" class="col col-md-4">
      <!-- module 1 content -->
    </div>
    <div id="module_2" class="col col-md-4">
      <!-- module 2 content -->
    </div>
    <div id="module_3" class="col col-md-4">
      <!-- module 3 content -->
    </div>
  </div>
</main>

Great! With Perfect Grid System™, this gives us a layout that displays as a single column on smaller screens, then switches to three columns at our medium breakpoint. Everyone is happy.

But then, someone sends in some feedback. Turns out that #module_1 is way more important to them than #module_2 or #module_3, so they’d like that to be in the middle column, and made larger. Easy enough:

<main>
  <div class="row">
    <div id="module_2" class="col col-md-3">
      <!-- module 2 content -->
    </div>
    <div id="module_1" class="col col-md-6">
      <!-- module 1 content -->
    </div>
    <div id="module_3" class="col col-md-3">
      <!-- module 3 content -->
    </div>
  </div>
</main>

Cool. We addressed the feedback! Except, as would be expected, other users are writing in with their own priorities. Some need #module_3 in the middle. Some want the original, three column layout back. Still others are asking for even more arrangements. Chaos! Perfect Grid System™ wasn’t really made to handle this. It’s time for a different approach.

The new school

CSS Grid Layout is a layout engine baked right into your browser—no third party dependencies required. Let’s revisit our dashboard, but with a couple of important modifications. First, we can remove all Perfect Grid System™-specific classes. We also no longer need its wrapper <div>, as we can apply our CSS Grid Layout styles directly to the parent <main> element.

<main class="grid">
  <div id="module_1">
    <!-- module 1 content -->
  </div>
  <div id="module_2">
    <!-- module 2 content -->
  </div>
  <div id="module_3">
    <!-- module 3 content -->
  </div>
</main>

With this simplified markup, we can now deploy our CSS Grid Styles.

Here’s our original three column layout in CSS Grid:

.grid {
  display: grid;
  grid-column-gap: 1rem;
  grid-template-columns: repeat(3, 1fr);
}

Notice that we defined the grid at the top-level .grid element, and didn’t define any explicit styles for our modules. CSS Grid is pretty smart, and knows to place our three #module_ elements within the three columns without any further input from us.

What about switching #module_1 and #module_2 like before?

.grid {
  display: grid;
  grid-column-gap: 1rem;
  grid-template-columns: 1fr 2fr 1fr;
}

#module_1 {
  order: 2;
}

#module_2 {
  order: 1;
}

#module_3 {
  order: 3;
}

We increased the size of the middle column to be twice as large as the other two. We also explicitly defined the order of our #module_s, which can be used to tell CSS Grid how to visually order the elements without affecting their source order. This is all fine and dandy, but how do we handle the case where multiple users or organizations want their own layout flavor?

At Revalize, we tackled this problem with a data-layout attribute on the parent grid element, and a simple user account setting to change it. Here’s an interactive example (best viewed directly on CodePen):

See the Pen bshow multiple layouts with css grid by Bobby Showalter (@bobbyshowalter) on CodePen.

First, let’s examine the markup.

<main class="grid js-grid" data-layout="1">
  <div id="module_1">
    <span>1</span>
  </div>
  <div id="module_2">
    <span>2</span>
  </div>
  <div id="module_3">
    <span>3</span>
  </div>
</main>

Just as before, our markup is lean and straightforward, free of any intent-obscuring layout information. And here’s the CSS Grid magic that drives the multiple layout examples:

@media screen and (min-width: 60rem) {
  /* parent grid settings */
  .grid {
    display: grid;
    align-items: start;
    grid-column-gap: 1rem;
  }

  /* layout 1 styles */
  .grid[data-layout="1"] {
    grid-template: min-content / 15rem 1fr 15rem;
  }

  /* layout 2 styles */
  .grid[data-layout="2"] {
    grid-template: repeat(2, min-content) / 1fr 15rem;
  }

  .grid[data-layout="2"] #module_1 {
    grid-area: 1 / 1 / 2 / 2;
  }

  .grid[data-layout="2"] #module_2 {
    grid-area: 2 / 1 / 3 / 2;
  }

  .grid[data-layout="2"] #module_3 {
    grid-area: 1 / 2 / 3 / 3;
  }

  /* layout 3 styles */
  .grid[data-layout="3"] {
    grid-template: repeat(3, min-content) / 100%;
  }
}

Once the screen is larger than our prescribed breakpoint (60rem, in this case), we turn on the grid. Then, in just a few lines of CSS and scoped to the various data-layout options, we can present our content in multiple layouts without having to touch the markup source. Where possible, we let the browser do the heavy lifting and place the #module_s on its own; otherwise, we use the grid-area property to explicitly place our #module_s.

This approach is a marked improvement over the “old” way because it better separates our concerns, and makes further updates more seamless. Now, instead of chasing markup templates or crazy if / else if / else statements all over our content, we can capture layout information alongside the rest of our org- or user-specific presentation styles, where it belongs.