DEV Community

Cover image for CSS subgrid: Designing advanced layouts
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

CSS subgrid: Designing advanced layouts

Written by Ibadehin Mojeed✏️

Over time, CSS has evolved significantly, providing web developers with tools for designing complex and flexible layouts. Among the latest additions to CSS is the subgrid feature, which enhances the capabilities of grid layouts.

In this guide, we'll look at practical applications of CSS subgrid. We’ll explore situations where it is a better choice than the regular nested Grid, and see how to use it to make interesting and advanced layouts. Before you dive in, make sure you're comfortable with CSS grid.

Challenges with CSS grid before subgrid

CSS grid has been amazing, solving many layout issues seamlessly. Nevertheless, when it comes to certain layouts, you might encounter limitations, especially when attempting to implement nested grids — that is, grids inside another grid.

Consider the layout example below: Blog Post Layout Example Usually, to set up the above structure, we'd employ a CSS grid to place the immediate items, such as the cards, inside the grid tracks. Additionally, we might use a nested grid to organize the card contents. However, because of how CSS grid works, the contents within each card may not align uniformly across. This happens because nested grids operate independently of each other and the parent grid.

In many situations, this isn't an issue. However, there are times when the layout calls for a consistent alignment, as shown in the design below: Blog Layout With Consistent Alignment

To guarantee proper alignment of the nested grid contents, it is essential they use a shared grid track. Recognizing this limitation with the traditional nested grid, CSS grid Level 2 introduced the subgrid feature to overcome this challenge.

Using CSS subgrid

CSS subgrid allows nested grid items to participate in the sizing of the tracks defined in their parent grid. This means that the tracks of a grid item can align with the tracks of the parent grid, resulting in a more flexible layout system.

Before delving into a more advanced layout demonstration, let's familiarize ourselves with CSS subgrid's browser support, syntax, and use cases.

Basic syntax and usage

subgrid is a value that we specify for grid-template-columns and/or grid-template-rows instead of creating a list of grid tracks:

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 100px 200px;
}

.subgrid {
  display: grid;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}
Enter fullscreen mode Exit fullscreen mode

When we apply the subgrid value in a nested grid, what we're essentially saying is: "I want to be my own grid, but I want to adopt the grid tracks from the parent grid."

Keeping this idea in mind, let's look at a straightforward example. Consider the following HTML structure:

<div class="grid">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
  <div class="item">Item 4</div>
  <div class="subgrid">
    <div class="item">Item 5_1</div>
    <div class="item">Item 5_2</div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Our goal is to align the items of .subgrid with the items in the parent grid. Here's what we expect: Aligning Subgrid Elements Within The Parent Grid If we opted for a regular nested grid, we would have to carefully configure the columns of the subgridded items to align precisely with those of the parent. The same applies to the gap size:

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  padding: 1rem;
  background-color: #aba7a7;
}

.subgrid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-column: span 2;
  gap: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

Check it out on CodePen.

With the subgrid feature, we employ grid-template-columns: subgrid to indicate that, rather than creating a new track listing, the subgrid should adopt the column tracks defined in the parent grid:

.grid {
  /* same as before */
}

.subgrid {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: span 2;
}
Enter fullscreen mode Exit fullscreen mode

Note that we aren't specifying a gap size. The subgrid automatically inherits the parent grid's gap and line names (if available). If necessary, we can also override them within the subgrid:

See this example on CodePen.

subgrid introduces a new level of flexibility to grid layouts. As you will observe in the following sections, this feature will offer us control over grid layouts that were previously challenging to achieve.

Implementing CSS subgrid in real projects

Now that we have a grasp of the fundamentals of CSS subgrid, let's delve into how to apply it in real world projects. We'll walk through two examples: a responsive card-based layout and a responsive post listing layout.

Responsive card-based layout

Using the following HTML structure, we have a card-based layout where each card is comprised of a title, image, text contents, and an action link:

<section>
  <div class="card">
    <div class="flex">
      <h2>Find out how much</h2>
      <img />
    </div>
    <div class="content">some text</div>
    <div class="action">try it out</div>
  </div>
  <div class="card"><!-- ... --></div>
  <div class="card"><!-- ... --></div>
  <div class="card"><!-- ... --></div>
</section>
Enter fullscreen mode Exit fullscreen mode

Here is the CSS:

section {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(350px, 100%), 1fr)
  );
  gap: 1rem;
  /* ... */
}

.card {
  display: grid;
  border: 1px solid #cacaca;
  border-radius: 6px;
  padding: 16px;
}

/* Some other styles */
Enter fullscreen mode Exit fullscreen mode

We have a layout as follows: Card Based Layout Example When creating a layout like this, each card can have its own nested grid structure within the parent grid. The issue with using a regular nested grid is the lack of consistent alignment among the card items: Nested Grid Structure  

See the CodePen.

With subgrid, we can create a clean and organized layout. In the code below, we use grid-template-rows: subgrid; on the card class, signifying that it will inherit the row sizes from its parent grid, which, in this case, is the section element:

section {
  /* ... */
  grid-template-rows: auto 1fr auto;
}

.card {
  display: grid;
  /* ... */
  grid-template-rows: subgrid;
  grid-row: span 3;
}
Enter fullscreen mode Exit fullscreen mode

As we've specified grid-row: span 3; for the card class, it will span three rows in the parent grid, ensuring that the first, second, and third rows align correctly: Ensuring Correct Alignment Of Grids As mentioned earlier, gaps are inherited in the subgrid. Take note of the space between the title and the description. We have the option to override the gap with a different one in the subgrid:

.card {
  /* ... */
  gap: 5px;
}
Enter fullscreen mode Exit fullscreen mode

See the CodePen.

Responsive layout for blog post listings

Now, let's build the example layout that was mentioned at the beginning of this lesson: Responsive Layout For Blog Post Listings Below is the HTML structure for the layout:

<main>
  <article>
    <img
      src="https://images.unsplash.com/photo-1524758631624-e2822e304c36?crop=entropyq=80&w=400"
      alt=""
    />

    <h2 class="p7">Lorem ipsum dolor sit</h2>
    <div class="read__more">Read more</div>
  </article>
  <article><!-- ... --></article>
  <article><!-- ... --></article>
  <article><!-- ... --></article>
  <article><!-- ... --></article>
</main>
Enter fullscreen mode Exit fullscreen mode

Using a regular nested grid

As expected, the nested grid items — in this case, the article items — won't automatically adopt the parent tracks. Consequently, we need to manually configure each item with specific row definitions.

In this instance, we can utilize grid-template-rows or grid-auto-rows on the nested grid, as shown below:

main {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(300px, 100%), 1fr)
  );
  gap: 1rem;
  grid-auto-flow: dense;
}

article {
  display: grid;
  grid-auto-rows: 180px 1fr auto;
  /* ... */
}

img {
  /* ... */
  height: 180px;
}
/* other css rules */
Enter fullscreen mode Exit fullscreen mode

Here is the resulting CodePen.

In the row definition, the first row has a fixed height equal to the image height. The second row, defined as 1fr, will take up the available space and grow proportionally. The third row, set to auto, will adjust its height based on its contents.

See the result below: Nested Items Are Aligned Independently Of Each Other Although the nested items might appear aligned, they are, in fact, independent of each other. The alignment is due to the fixed height of the first row, and the title taking up the available space and growing proportionally. If, for instance, the text on the third row were to span multiple rows, the alignment would be distorted: Text Spanning Multiple Rows Distorting Alignment

Using subgrid

Instead of defining the row tracks on the article, we can delegate the definition to its parent grid, which is main. This allows all the article items to adopt their track sizing from that parent grid by using grid-template-rows: subgrid;:

main {
  /* ... */
  grid-auto-rows: 180px 1fr auto;
}

article {
  /* ... */
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  row-gap: 0px;
}
Enter fullscreen mode Exit fullscreen mode

Using grid-row: span 3; allows the article to expand vertically, accommodating its contents without causing any overlap: Using Subgrid To Accomodate The Layout Without Overlap

subgrid in both directions

So far in our project, only the row tracks of the nested grid use the tracks defined on the parent, thanks to grid-template-rows: subgrid. The column tracks, however, still behave like a regular nested grid.

Upon revisiting the final project, we notice that some cards span two columns and may include a description. To ensure the description also aligns with the parent grid column track, we'll utilize grid-template-columns: subgrid.

Let's modify the card markup to include an optional description text:

<main>
  <article data-custom="true">
    <img... />
    <h2 class="p7">...</h2>
    <div class="description">
      Lorem ipsum dolor sit amet elit dolor consectetur elit
      dolor amet ande.
    </div>
    <div class="read__more">Read more</div>
  </article>
  ...
  <article><!-- ... --></article>
</main>
Enter fullscreen mode Exit fullscreen mode

We've also introduced a custom data-* attribute to any article element that we want to style differently. This allows us to target them with article[data-custom='true'] and apply styles accordingly. Alternatively, you may use a class attribute for this purpose.

By default, we can hide the description for smaller screens:

.description {
  display: none; /* Hide description by default */
  font-size: 13px;
  padding: 0 7px 7px;
}
Enter fullscreen mode Exit fullscreen mode

And we can use a media query to display it on larger screens:

article[data-custom='true'] {
  @media (min-width: 996px) {
    .description {
      display: block;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

We’ve employed native CSS nesting to nest the @media and the selector.

Next, we'll ensure that the selected articles span two columns in their parent grid. Afterward, we'll apply subgrid so that they inherit their sizing from the columns of the parent grid:

article[data-custom='true'] {
  @media (min-width: 996px) {
    grid-column: span 2;
    grid-template-columns: subgrid;

    .description {
      display: block;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The nested grid items now look up to the parent grid for their placement: Nested Grid Looking To Parent Grid For Their Placement Now, let's ensure that both the image and title take up the entire width of the card:

article[data-custom='true'] {
  @media (min-width: 996px) {
    grid-column: span 2;
    grid-template-columns: subgrid;

    > img {
      grid-column: 1 / -1;
    }

    > h2 {
      grid-column: 1 / -1;
      font-size: 30px;
    }

    .description {
      display: block;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

We've utilized grid-column: 1 / -1; to span the image and title from the first to the last column in the grid: Image And Title Spanning The Entire Card Width The project works fine and is responsive. See it yourself in the CodePen below:

See the CodePen.

Conclusion

CSS subgrid introduces an improved level of flexibility and control to grid layouts that were previously challenging to achieve. By understanding its syntax and exploring different use cases, we’ve learned how to leverage this feature to create advanced designs.

If you enjoyed reading this guide, share the post around the web. And if you have questions or recommendations, please share your thoughts in the comment section.


Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.

LogRocket Signup

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — Start monitoring for free.

Top comments (0)