Search code examples
htmlcssflexboxcss-grid

Fix elements to viewport top


This is kind of a weird predicament, because I ended up using flexbox to align menu items in my sidenav and header, as well as grid to display/allocate space for my nav and header components.

I've tried methods for making solely grid or flexbox based sidebars (or headers) be sticky but they don't work at all.

Here's an example of what I have:

<div class="grid-container">
    <nav>
        <div class="menu-item">Link</div>
    </nav>
    <div class="header"> Header Content Here </div>
    <main> Main Section. This should be able to scroll while Nav and 
           Header are sticking to the top
    </main>
</div>

CSS:

.grid-container {
    grid-template-columns: 200px 1fr;
    grid-template-areas: 
      "sidenav header"
      "sidenav main";
      box-shadow: 5px 10px !important;
  }

nav {
  grid-area: sidenav;
  box-shadow: 0 -1px 12px 2px whitesmoke;
  background-color: white;
  display: none;
  z-index: 100;
  flex-direction: column;
}

.header {
  grid-area: header;
  background-color: #f8f9ff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0px 16px;
}

main {
  grid-area: main;
  background-color: #f8f9ff;
}

Solution

  • Combining grid and flexbox properties like you are trying to do is the right thing - you need to add a bit more to make them work:

    • add viewport height to your grid so that you can make your header and sidebar sticky.
    • you can specify your header height using grid-template-rows (see snippet below)
    • add overflow-y: auto to force only the main to overflow.

    See demo below:

    body  {
      margin: 0;
    }
    
    .grid-container {
      display: grid;
      height: 100vh; /* Add total height of the grid */
      grid-template-columns: 200px 1fr; /* sets sidenav width */
      grid-template-rows: 75px 1fr; /* sets header height */
      grid-template-areas: "sidenav header" "sidenav main";
      box-shadow: 5px 10px !important;
    }
    
    nav {
      grid-area: sidenav;
      box-shadow: 0 -1px 12px 2px whitesmoke;
      background-color: white;
      z-index: 100;
      border: 1px solid;
    }
    
    .header {
      grid-area: header;
      background-color: #f8f9ff;
      display: flex; /* flexbox to center items */
      align-items: center;
      justify-content: space-between;
      padding: 0px 16px;
      border: 1px solid;
    }
    
    main {
      grid-area: main;
      background-color: #f8f9ff;
      border: 1px solid;
      overflow-y: auto; /* add scrolling */
    }
    <div class="grid-container">
      <nav>
        <div class="menu-item">Link</div>
      </nav>
      <div class="header"> Header Content Here </div>
      <main> Main Section. This should be able to scroll while Nav and Header are sticking to the top<br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here
        <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum
        some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/>    Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some
        text here <br/> Lorel ipsum some text here <br/> Lorel ipsum some text here <br/>
      </main>
    </div>