CSS Grid Gap Behavior with Hidden Elements

Posted on February 14, 2023
Takes about 4 minutes to read

I was recently prototyping a component layout that included a way to toggle the visibility of sibling elements inside a grid display. What tripped me up was, while these elements were hidden, all of the container's gap gutters remained, leaving undesired extra visual spacing. I expected these gutters to collapse. The reason they stick around is related to explicitly defining grid templates.

Template or auto layout?

What are the differences between grid-template-* and grid-auto-* when declared for columns or rows in a grid layout? Ire Aderinokun has a fantastic article that thoroughly explains these distinctions and I recommend giving it a read. I'll try to quickly summarize: grid-template-* sets explicit column and row tracks, while grid-auto-* creates implicit track patterns.

The following excerpt in the "How grid-auto works" section from the article stood out to me:

Unlike the grid-template-* properties, the grid-auto-* properties only accept a single length value.

After some experimentation and confirming through examples from the Syntax section in the grid-auto-rows MDN web docs, I found that multiple track-size values can be used as well. Let's try an example to create a layout commonly referred to as the pancake stack. Its value of auto 1fr auto will either:

Visualize the gap

In the CodePen demo below, tick on the "Hide elements" checkbox to assign display: none on all but the first two elements in both grid containers.

Open CodePen demo

So what's happening here? When collapsed, the grid-template-rows container is slightly taller than its grid-auto-rows counterpart because of the extra space appearing beneath the remaining visible elements. Recall that rows are explicitly set with grid-template-rows. In this situation, the gap gutters still apply even when elements are hidden or removed from the container.

I ended up moving forward with grid-auto-rows for my component's layout needs. You can see a stripped down version of it in the CodePen below. The classic small screen navigation!

Open CodePen demo

A template solution

If using grid-template-* is preferred or necessary, the solution is to override the property value to match the expected visual result. The above demo could even get by on a single ruleset that applies the template only when the menu is open:

.nav.is-open {
  grid-template-rows: auto 1fr auto;
}

This same solution can also work for grid-template-areas. While it leads to writing more code, it self-documents really nicely.

.nav {
  grid-template-areas: "logo toggle";
}

.nav.is-open {
  grid-template-areas:
    "logo toggle"
    "menu menu"
    "cta  cta";
}

.nav .logo {
  grid-area: logo;
}
.nav .toggle {
  grid-area: toggle;
}
.nav .menu {
  grid-area: menu;
}
.nav .cta {
  grid-area: cta;
}

Helpful resources

Back to all blog posts