a drafting schematic of a series of columns of different sizes --ar 3:2

Footer Link Columns With Subgrid

In this post, I’ll provide some background on why I tried this and explain how a subgrid works. However, you can skip that and go straight to the final implementation code if you’d like.

At work, I recently received a design to clean up the footer of the DataCamp site. It’s a large collection of links spread across six columns, with titles over each section. We’re also adding localization throughout the site, so my first question was, “What should this look like when the titles wrap?”

Screenshot of a footer with six columns of links in English

The answer offered an opportunity to try something new. The intent behind the design is that if one of the top titles wrap, then all of the links shift down and start at the same vertical point. To achieve this, I either need to control the height of the first title in each column or I have to use some approach that “knows” it.

Screenshot of a footer with six columns of links in English

Controlling the first titles via min-height is fragile and something I’ve done in the past, but the platform continues to evolve to make things like this natural. There’s a way to do this with Grid itself, if I was to use grid-area, but it would be a lot of specific code. I’m going to share an example of the code for the full version, based on CSS grid generator, but I’d have to set these for when there’s two, three, four, and then the six columns. Achievable, but gnarly.

.parent {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: auto 1fr;
  grid-column-gap: 0px;
  grid-row-gap: 0px;
}

.div1 { grid-area: 1 / 1 / 2 / 2; }
.div2 { grid-area: 2 / 1 / 3 / 2; }
.div3 { grid-area: 1 / 2 / 2 / 3; }
.div4 { grid-area: 2 / 2 / 3 / 3; }
.div5 { grid-area: 1 / 3 / 2 / 4; }
.div6 { grid-area: 2 / 3 / 3 / 4; }
.div7 { grid-area: 1 / 4 / 2 / 5; }
.div8 { grid-area: 2 / 4 / 3 / 5; }
.div9 { grid-area: 1 / 5 / 2 / 6; }
.div10 { grid-area: 2 / 5 / 3 / 6; }
.div11 { grid-area: 1 / 6 / 2 / 7; }
.div12 { grid-area: 2 / 6 / 3 / 7; }

I heard subgrid is good

I’ve seen some interesting posts about subgrid, but this is the first time I have found a reason to use it. I went back over the CSS Subgrid article on web.dev and tried applying it. I thought I’d need to use some form of minmax, on the first row, but I couldn’t get it to behave how I wanted. So, I took to Twitter, where Adam Argyle helped me out.

Span

The value that I was missing was span, which, in this case, will set how many rows the grid should “span” over. You can specify a starting row, but we’re allowing it to default to the first row in this example.

The formal definition on MDN is:

Contributes a grid span to the grid item’s placement such that the corresponding edge of the grid item’s grid area is n lines from the opposite edge.

Here’s some code to visualize how it works. The style block here is real, so you can edit the code and see how it affects the UI. Or, here’s a pen.

Adam’s example worked perfectly for that initial example, but I made the example too simple. The columns are going to have multiple links, and technically each link is a row item with the way this markup was created.

If the markup looks something like this, I’d need to set a span value high enough to cover all of the links. That starts to feel fragile, in the way a min-height on the titles would. I’m not sure a future engineer would know to change that value. I could do something crazy like throw a high number that would likely never get hit, but I’m trying to avoid hacks and use the platform the best that I can.

<section class="example-grid">
  <nav class="example-subgrid-multiple" role="navigation" aria-label="Column One Navigation">
    <h3>Column One</h3>
    <a href="#">Links should align vertically</a>
  </nav>
  <nav class="example-subgrid-multiple" role="navigation" aria-label="Column Two Navigation">
    <h3>Column Two's Title Is Longer</h3>
    <a href="#">Links should align vertically</a>
    <a href="#">Links should align vertically</a>
  </nav>
  <nav class="example-subgrid-multiple" role="navigation" aria-label="Column Three Navigation">
    <h3>Column Three</h3>
    <a href="#">Links should align vertically</a>
    <a href="#">Links should align vertically</a>
    <a href="#">Links should align vertically</a>
  </nav>
  <nav class="example-subgrid-multiple" role="navigation" aria-label="Column Four Navigation">
    <h3>Column Four</h3>
    <a href="#">Links should align vertically</a>
    <a href="#">Links should align vertically</a>
    <a href="#">Links should align vertically</a>
    <a href="#">Links should align vertically</a>
  </nav>
</section>

Here, if you change the value to less than 5 you’ll that the links start to pile on top of each other and if you set it to anything higher than 5 you’ll see that it starts to add space based on the gap.

If we use another HTML element to wrap the links, we can reduce the rows that we need to span. To avoid using a div, we can wrap them in a ul. Here’s the markup:

<section class="example example-grid">
  <nav class="example-subgrid-ul" role="navigation" aria-label="Column One Navigation">
    <h3>Column One</h3>
    <ul>
      <li><a href="#">Links should align vertically</a></li>
    </ul>
  </nav>
  <nav class="example-subgrid-ul" role="navigation" aria-label="Column Two Navigation">
    <h3>Column Two's Title Is Longer</h3>
    <ul>
      <li><a href="#">Links should align vertically</a></li>
      <li><a href="#">Links should align vertically</a></li>
    </ul>
  </nav>
  <nav class="example-subgrid-ul" role="navigation" aria-label="Column Three Navigation">
    <h3>Column Three</h3>
    <ul>
      <li><a href="#">Links should align vertically</a></li>
      <li><a href="#">Links should align vertically</a></li>
      <li><a href="#">Links should align vertically</a></li>
    </ul>
  </nav>
  <nav class="example-subgrid-ul" role="navigation" aria-label="Column Four Navigation">
    <h3>Column Four</h3>
    <ul>
      <li><a href="#">Links should align vertically</a></li>
      <li><a href="#">Links should align vertically</a></li>
      <li><a href="#">Links should align vertically</a></li>
      <li><a href="#">Links should align vertically</a></li>
    </ul>
  </nav>
</section>

This allows us to achive the columns with two rows, which I set the subgrid to span over.

Final Version

I had simplified the solution too far for the specific tweet, but either way the answer was correct and super helpful. I’m so thankful for the people in our community. Here, I’m showing a version that matches up what I need to do. (Unfortunately, mine got even more convoluted since it was a shared React component, but that just requires more refactoring because of our choices.)

I don’t know of a way to avoid nesting a div here so I’m super open to ideas. I want to keep the span limited to the title row and the content row, so the div wraps all of the content.

<section class="example example-grid">
  <nav class="example-subgrid-sets" role="navigation" aria-label="Column One Navigation">
    <h3>Column One</h3>
    <div>
      <ul>
        <li><a href="#">Links should align vertically</a></li>
      </ul>
      <h3>This one has another set</h3>
      <ul>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
      </ul>
    </div>
  </nav>
  <nav class="example-subgrid-sets" role="navigation" aria-label="Column Two Navigation">
    <h3>Column Two's Title Is Longer</h3>
    <div>
      <ul>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
      </ul>
      <h3>This one has another set</h3>
      <ul>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
      </ul>
    </div>
  </nav>
  <nav class="example-subgrid-sets" role="navigation" aria-label="Column Three Navigation">
    <h3>Column Three</h3>
    <div>
      <ul>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
      </ul>
    </div>
  </nav>
  <nav class="example-subgrid-sets" role="navigation" aria-label="Column Four Navigation">
    <h3>Column Four</h3>
    <div>
      <ul>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
        <li><a href="#">Links should align vertically</a></li>
      </ul>
    </div>
  </nav>
</section>

I’m including the original grid code here too, just so this could be copied.

Big thank you to Adam for the tip! It helped me with figuring out the fix, learning something new, and inspired a blog post.