CSS subgrid: Designing advanced layouts
Tags: css, webdev
Published: 2023-12-19 17:32:37

**Written by [Ibadehin Mojeed](https://blog.logrocket.com/author/ibadehinmojeed/)✏️**

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](https://blog.logrocket.com/css-grid-guide/).

## 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](https://blog.logrocket.com/wp-content/uploads/2023/12/blog-post-layout-example.jpeg) 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](https://blog.logrocket.com/wp-content/uploads/2023/12/blog-layout-consistent-alignment.jpeg) 

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](https://caniuse.com/css-subgrid), 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:

```css
.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;
}
```

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:

```html
<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>
```

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](https://blog.logrocket.com/wp-content/uploads/2023/12/aligning-subgrid-elements-within-parent-grid.png) 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:

```css
.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;
}
```

[Check it out on CodePen](https://codepen.io/ibaslogic/pen/bGzMabW).

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:

```css
.grid {
  /* same as before */
}

.subgrid {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: span 2;
}
```

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](https://codepen.io/ibaslogic/pen/LYqmqMO).

`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:

```html
<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>
```

Here is the CSS:

```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 */
```

We have a layout as follows: ![Card Based Layout Example](https://blog.logrocket.com/wp-content/uploads/2023/12/card-based-layout-example.png) 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](https://blog.logrocket.com/wp-content/uploads/2023/12/nested-grid-structure.png)  

[See the CodePen](https://codepen.io/ibaslogic/pen/JjxvgXV).

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:

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

.card {
  display: grid;
  /* ... */
  grid-template-rows: subgrid;
  grid-row: span 3;
}
```

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](https://blog.logrocket.com/wp-content/uploads/2023/12/ensuring-correct-alignment-grids.png) 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:

```css
.card {
  /* ... */
  gap: 5px;
}
```

[See the CodePen](https://codepen.io/ibaslogic/pen/ExrLqEB).

### 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 ](https://blog.logrocket.com/wp-content/uploads/2023/12/responsive-layout-blog-post-listings.jpeg) Below is the HTML structure for the layout:

```html
<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>
```

### 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:

```css
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 */
```

[Here is the resulting CodePen](https://codepen.io/ibaslogic/pen/wvNXwJY).

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](https://blog.logrocket.com/wp-content/uploads/2023/12/nested-items-aligned-independently.jpeg) 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](https://blog.logrocket.com/wp-content/uploads/2023/12/text-spanning-multiple-rows-distorting-alignment.png)

### 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;`:

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

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

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](https://blog.logrocket.com/wp-content/uploads/2023/12/using-subgrid-accomodate-layout-without-overlap.jpeg)

## 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:

```html
<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>
```

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:

```css
.description {
  display: none; /* Hide description by default */
  font-size: 13px;
  padding: 0 7px 7px;
}
```

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

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

We’ve employed [native CSS nesting](https://blog.logrocket.com/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:

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

    .description {
      display: block;
    }
  }
}
```

The nested grid items now look up to the parent grid for their placement: ![Nested Grid Looking To Parent Grid For Their Placement](https://blog.logrocket.com/wp-content/uploads/2023/12/nested-grid-parent-grid-placement.png) Now, let's ensure that both the image and title take up the entire width of the card:

```css
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;
    }
  }
}
```

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](https://blog.logrocket.com/wp-content/uploads/2023/12/image-title-spanning-card-width.jpeg) The project works fine and is responsive. See it yourself in the CodePen below:

[See the CodePen](https://codepen.io/ibaslogic/pen/JjxZjGp).

## 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](https://lp.logrocket.com/blg/css-signup).

[![LogRocket Signup](https://blog.logrocket.com/wp-content/uploads/2019/12/cpu-memory-usage.png)](https://lp.logrocket.com/blg/css-signup)

[LogRocket](https://lp.logrocket.com/blg/css-signup) 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](https://lp.logrocket.com/blg/css-signup).