htmlcsspositioncss-gridsticky

How to use CSS Grid with sticky header/sidebar and a non-overlapping footer?


I’m trying to build a layout using CSS Grid with:

It should behave like StackOverflow’s layout: the header and sidebar stick while scrolling, but when the footer comes into view, the layout shouldn’t break.

Here’s what I tried:

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  text-align: center;
}

.container {
  display: grid;
  grid-template-areas: "header header" "aside main" "footer footer";
  grid-template-columns: 20% 80%;
}

header {
  grid-area: header;
  background: red;
  min-height: 80px;
  position: sticky;
  top: 0;
}

aside {
  grid-area: aside;
  background: green;
  position: sticky;
  top: 80px;
  height: 100vh;
  font-size: 20px;
}

main {
  grid-area: main;
  background: blue;
  height: 150vh;
  font-size: 20px;
}

footer {
  grid-area: footer;
  background: darkcyan;
  height: 80px;
}
<div class="container">
  <header>
    <h1>Hello</h1>
  </header>
  <aside>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    </p>
  </aside>
  <main>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
    </p>
  </main>
  <footer>
    <h1>Footer</h1>
  </footer>
</div>

With this code, the header and sidebar stick correctly, but when I scroll to the footer, the sidebar overlaps and the layout “breaks.”

Question: How can I make the sidebar and header sticky with CSS Grid, but still have the footer appear correctly at the bottom without overlap?


Solution

  • make the content inside the aside sticky and increase the z-index of header:

    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
      text-align: center;
    }
    
    .container {
      display: grid;
      grid-template-areas: "header header" "aside main" "footer footer";
      grid-template-columns: 20% 80%;
    }
    
    header {
      grid-area: header;
      background: red;
      min-height: 80px;
      position: sticky;
      z-index:1;
      top: 0;
    }
    
    aside {
      grid-area: aside;
      background: green;
      font-size: 20px;
    }
    aside > p {
      position: sticky;
      top: 80px;
    }
    
    main {
      grid-area: main;
      background: blue;
      height: 150vh;
      font-size: 20px;
    }
    
    footer {
      grid-area: footer;
      background: darkcyan;
      height: 80px;
    }
    <div class="container">
      <header>
        <h1>Hello</h1>
      </header>
      <aside>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
        </p>
      </aside>
      <main>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
        </p>
      </main>
      <footer>
        <h1>Footer</h1>
      </footer>
    </div>