CSS Grid Gap Behavior with Hidden Elements

Some discoveries on how the CSS gap property operates when hiding items in grid-template & grid-auto layouts

Posted on Feb 14, 2023

Takes about 3 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.

See the pen (@hexagoncircle) on CodePen.

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!

See the pen (@hexagoncircle) on CodePen.

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 {
"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

Webmentions for this post

5 mentions
  • Brandon

    @hexagoncircle yep just another reason why CSS grid is maniacal. Imagine a "grid-gap-behavior: collapse;" property 😥

  • Victor Foster

    Such a great read on CSS grid templates

  • Pablo Lara H

    🔴🟣 CSS Grid Gap Behavior with Hidden Elements by Ryan Mulligan @hexagoncircle @hexagoncircle@fosstodon.org #CSS #cssgridgap #webdev ryanmulligan.dev/blog/grid-gap/

  • 황규연 / Kyooyeon Hwang

    숨겨진 요소가 있는 CSS 그리드 간격 동작 grid-template 및 grid-auto 레이아웃에서 항목을 숨길 때 CSS 간격 속성이 작동하는 방식에 대한 몇 가지 발견 (그냥 그리드 관련 글인가 궁금했는데 그리드에 대한 정보를 또 하나 발견... )

  • Frontend Dogma

    CSS Grid Gap Behavior with Hidden Elements, by @hexagoncircle@fosstodon.org: ryanmulligan.dev/blog/grid-gap/