jordanmmck
jordanmmck

Reputation: 115

position sticky top and bottom

Is there a way to update this gist such that the side menu nav extends to the bottom of the viewport during scroll, until it is pushed up by the footer? It should also maintain its current position: sticky behaviour of sticking to the top of the viewport.

Edit 1: yes this is a duplicate of the problem linked below, but the answers given in the linked post don't actually solve the problem!

Edit 2: to clarify: what I'm trying to achieve is simply a side-navigation element that takes up the full height available to it. As you scroll down the element should "stick" to the top of the viewport (this is what position: sticky with top:0 does perfectly. Similarly, as you scroll down the bottom of the element should grow downward -- it should stick to the bottom of the viewport, until you scroll so far down that the footer starts pushing the element up (at which point it should shrink). Basically I want a side-nav that takes up as much space in the viewport as possible, but never expands outside the viewport. If it has inside it more content than can fit in the viewport, then this overflow should become scrollable -- but the entire element is always within the bounds of the viewport!

Edit 3: I've uploaded a video to youtube. See the top and bottom markers? That is exactly where I would like the top and and bottom of my side-nav element to be. Basically I'd like the element to always be sandwiched right between TOP and BOTTOM.

[This is basically a re-post of this question... Sorry about that, but no answer was provided there, and I've been stuck on this for days.]

The effect I'm hoping for would sort of be like position: sticky with top and bottom trigger points... See screenshot below from the original post. I'm basically trying to build a side-nav like this one on the gitbook site.

Pure CSS would be awesome, but if JS is needed then that's fine too! Please help!

enter image description here

Upvotes: 3

Views: 3439

Answers (1)

peekolo
peekolo

Reputation: 342

Edited: to affect divs on both left and right.

I'm uncertain of the effect you want as the gitbook site has its left nav much shorter than the main content, whilst your left nav is much longer than the main content. Here's a go at what I think you are trying to achieve - with javascript.

*Edited to meet OP's clarification of requirements.

Change your css to

    .page-layout-nav,
    .page-layout-aside {
      position: sticky;
      top: 0px;
      bottom:1px;
      overflow: auto;
      height: 100vh;
    }

Then try using this script to adjust the height of the left nav during scroll.

    var doch = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);

    document.addEventListener("DOMContentLoaded", function() {
      var onav = document.getElementsByClassName('page-layout-nav')[0];
      var onavr = document.getElementsByClassName('page-layout-aside')[0];
      var doch = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
      topspace = window.scrollY + doch - 16 - 50 - 2;
      onav.style.height = topspace + "px";
      onavr.style.height = topspace + "px";

    });

    function update() {
      var onav = document.getElementsByClassName('page-layout-nav')[0];
      var onavr = document.getElementsByClassName('page-layout-aside')[0];
      var ofooter = document.getElementsByClassName('page-footer')[0];
      var threshold = window.scrollY + doch + 16;
      var topspace = 0;
      if (window.scrollY < 16 + 50) {
        topspace = window.scrollY + doch - 16 - 50 - 2;
        onav.style.height = topspace + "px";
        onavr.style.height = topspace + "px";
      } else if (threshold >= ofooter.offsetTop) {
        onav.style.height = doch - threshold + ofooter.offsetTop + "px";
        onavr.style.height = doch - threshold + ofooter.offsetTop + "px";
      } else {
        onav.style.height = (doch - 1) + "px";
        onavr.style.height = (doch - 1) + "px";
      }

    }

    window.addEventListener('scroll', update);

Here's the full code with runnable result:

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>GistRun</title>
  <style>
    * {
      box-sizing: border-box;
    }
    
    html,
    body {
      margin: 0;
      padding: 0;
    }
    
    .page-header,
    .page-footer {
      height: 50px;
      background-color: #ccc;
    }
    
    .page-layout {
      display: flex;
      justify-content: space-between;
      align-items: flex-start;
      margin: 16px 0;
    }
    
    .page-layout-nav,
    .page-layout-main,
    .page-layout-aside {
      border: 1px dotted;
    }
    
    .page-layout-nav {
      order: 0;
      width: calc(25% - 16px);
    }
    
    .page-layout-main {
      order: 1;
      width: 50%;
    }
    
    .page-layout-aside {
      order: 2;
      width: calc(25% - 16px);
    }
    
    .page-layout-nav,
    .page-layout-aside {
      position: sticky;
      top: 0px;
      bottom:1px;
      overflow: auto;
      height: 100vh;
    }
  </style>
</head>

<body>
  <header class="page-header">
    Contoso
  </header>
  
  <div class="page-layout">
    <main class="page-layout-main">
      <h1>Hello World</h1>
      <p>lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar.
        lorem ipsum sumit dolar. </p>
      <h2>Foo</h2>
      <p>lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar.
        lorem ipsum sumit dolar. </p>
      <h2>Bar</h2>
      <p>lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar.
        lorem ipsum sumit dolar. </p>
      <h2>Foo</h2>
      <p>lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar.
        lorem ipsum sumit dolar. </p>
      <h2>Bar</h2>
      <p>lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar. lorem ipsum sumit dolar.
        lorem ipsum sumit dolar. </p>
    </main>

    <nav class="page-layout-nav">
      <ul>
        <li><a href="#">1st foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
      </ul>
    </nav>

    <aside class="page-layout-aside">
      <h2>In this article</h2>
      <ul>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
        <li><a href="#">foo</a></li>
      </ul>
    </aside>
  </div>

  <footer class="page-footer">
    foo bar baz
  </footer>

  <script>
    var doch = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);

    document.addEventListener("DOMContentLoaded", function() {
      var onav = document.getElementsByClassName('page-layout-nav')[0];
      var onavr = document.getElementsByClassName('page-layout-aside')[0];
      var doch = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
      topspace = window.scrollY + doch - 16 - 50 - 2;
      onav.style.height = topspace + "px";
      onavr.style.height = topspace + "px";

    });

    function update() {
      var onav = document.getElementsByClassName('page-layout-nav')[0];
      var onavr = document.getElementsByClassName('page-layout-aside')[0];
      var ofooter = document.getElementsByClassName('page-footer')[0];
      var threshold = window.scrollY + doch + 16;
      var topspace = 0;
      if (window.scrollY < 16 + 50) {
        topspace = window.scrollY + doch - 16 - 50 - 2;
        onav.style.height = topspace + "px";
        onavr.style.height = topspace + "px";
      } else if (threshold >= ofooter.offsetTop) {
        onav.style.height = doch - threshold + ofooter.offsetTop + "px";
        onavr.style.height = doch - threshold + ofooter.offsetTop + "px";
      } else {
        onav.style.height = (doch - 1) + "px";
        onavr.style.height = (doch - 1) + "px";
      }

    }

    window.addEventListener('scroll', update);
  </script>
</body>

</html>

Upvotes: 1

Related Questions