skip to Main Content

I created a navbar with sticky. The idea is that, when the user scroll down, the navbar goes has relative position until the user scrolls up or when they reach the end of the webpage. I used javascript to add the sticky class during these two events. The problem I am facing is, since the navbar is being taken out of the document flow and having a fixed position- it is causing the entire webpage to shift up. To solve this I have added a pseudo element of same height that takes the place of navbar whenever sticky is activated. I want to know if this is the right way to solve this problem. Is this complicating the problem as I can solve this without a pseudo element just by using the position of my navbar as absolute. I am attaching part of my code for reference

function scrollDetect() {
  const navbar = document.getElementById("navbar");
  const placeholder = document.querySelector(".navbar-placeholder");
  let lastScroll = 0;

  window.addEventListener("scroll", () => {
    const currentScroll = document.documentElement.scrollTop || document.body.scrollTop;

    if (currentScroll > 0 && lastScroll <= currentScroll) {
      navbar.classList.remove("sticky");
      placeholder.style.display = "none"; // Hide the placeholder
    } else {
      navbar.classList.add("sticky", "z-index-999999");
      placeholder.style.display = "block"; // Show the placeholder to maintain space
    }

    lastScroll = currentScroll;

    if (currentScroll < 100) {
      navbar.classList.remove("sticky");
      placeholder.style.display = "none"; // Hide the placeholder
    }
  });
}

scrollDetect();
  .navbar-placeholder {
  height: 4.5rem;
  display: none;
}

.main-navbar {
  position: relative;
  display: inline-flex;
  width: 100%;
  top: 3.4rem;
  height: 4.5rem;
  align-items: center;
  justify-content: space-between;
  background-color: red;
}

.sticky {
  position: fixed;
  top: 0;
  width: 100%;
  animation: faceInEffect 0.3s;
  -webkit-animation: faceInEffect 0.3s;
  border-bottom: none;
}

@keyframes faceInEffect {
  from {
    top: -5rem;
  }
  to {
    top: 0rem;
  }
}

.content-for-scroll {
  position: relative;
  top: 100rem;
<div class="navbar-placeholder"></div>
<div class="main-navbar" id="navbar">
  <a>hello</a>
</div>

<div class="content-for-scroll">
  <a>hello</a>
</div>

2

Answers


  1. Yes this is way over complicated. Look at this example of using the css property position: sticky;. I have put a margin-top: 20px; on the <header> element to show an initial gap. The position of the <header> is relatively positioned until the viewport was scrolled such that the element would be less than 0px from the top. After that threshold, the <header> would be fixed to 0px from the top. There is no JS involved, although you can add JS to decide to add a sticky class based on some browser detected or user interaction event but this CSS feature is native and well supported.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Test Website</title>
        <style>
            body{
                background-color: rgb(159, 160, 168);
                padding: 0;
                margin:0;
            }
            header{
                display: flex;
                flex-direction: row;
                justify-content: flex-start;
                margin-top: 20px;
                background-color: rgb(5, 63, 164);
                position: sticky;
                top: 0;
                font-family: sans-serif;
            }
            h1{
                color: rgb(245, 177, 30);
                padding: 0 2rem;
                border-right: 1px solid rgb(245, 177, 30);
            }
            nav{
                display: flex;
                flex-direction: row;
                justify-content: space-evenly;
                flex: 1;
            }
            nav > a{
                display: flex;
                justify-content: center;
                align-items: center;
                padding: 0.5rem 2rem;
                font-size: 1rem;
                text-decoration: none;
                color:rgb(222, 222, 222);
                font-family: sans-serif;
                transition: all ease-in 0.2s;
            }
            nav > a:hover{
                color: rgb(245, 177, 30);
            }
            #featuredImage{
                height: 200px; width: auto;
            }
            main{
                display: flex;
                flex-direction: column;
                align-content: center;
                margin: 1rem 2rem
            }
            main section{
                display: flex;
                flex-direction: row;
                justify-content: center;
                background: rgb(167, 178, 178);
                border-radius: 4px;
                margin: 0.25rem;
                padding: 1rem;
            }
            .multi-section div{
                padding: 1rem;
                background: rgb(199, 193, 193);
                margin: 0.25rem;
                border-radius: 4px;
            }
            #long{
                margin-top: 1000px;
            }
        </style>
    </head>
    <body>
    <header>
        <h1><strong>Site Heading</strong></h1>
        <nav>
            <a href="/home">Home</a>
            <a href="/news">News</a>
            <a href="/support">Support</a>
            <a href="/about">About</a>
        </nav>
    </header>
    <main>
        <section>
            <h2>Heading</h2>
        </section>
        <section class="multi-section">
            <div>
                <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/CSS3_logo.svg/800px-CSS3_logo.svg.png" id="featuredImage">
            </div>
            <div>
                <p>Cascading Style Sheets (CSS) is a style sheet language used for describing the presentation of a document written in a markup language such as HTML or XML (including XML dialects such as SVG, MathML or XHTML).[1] CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript.[2]
    
                    CSS is designed to enable the separation of content and presentation, including layout, colors, and fonts.[3] This separation can improve content accessibility; provide more flexibility and control in the specification of presentation characteristics; enable multiple web pages to share formatting by specifying the relevant CSS in a separate .css file, which reduces complexity and repetition in the structural content; and enable the .css file to be cached to improve the page load speed between the pages that share the file and its formatting.</p>
            </div>
        </section>
        <section id="long">
            <p>Tester</p>
        </section>
    </main>
    
    </body>
    </html>

    See here for further reading on CSS position.

    Login or Signup to reply.
  2. Something terribly simple and really similar to the desired:
    toggle navigation bar on scroll-down and always show navigation on scroll-up — consists in using position sticky for the navigation element, and control the translate property (for the Y axis) via JavaScript that basically toggles a .is-hidden class:

    const elNav = document.querySelector("#navbar");
    let lastScrollY = 0;
    
    const toggleNav = () => {
      const isScrollDown = (lastScrollY - scrollY) < 0;
      const isDistant = scrollY > elNav.offsetHeight;
      const isBottom = scrollY + innerHeight === document.documentElement.scrollHeight;
      lastScrollY = scrollY;
      
      if (isBottom) {
        elNav.classList.remove("is-hidden");
      } else {
        elNav.classList.toggle("is-hidden", isDistant && isScrollDown);
      }
    };
    
    toggleNav(); // Do on init,
    addEventListener("resize", toggleNav); // on resize,
    addEventListener("scroll", toggleNav, {passive: true}); // and on scroll
    * { margin: 0; box-sizing: border-box; }
    body { font: 2rem/1.4 sans-serif; }
    nav, main, div { padding: 2rem; }
    
    /* NAVIGATION BAR */
    
    #navbar {
      position: sticky;
      top: 0;
      left: 0;
      width: 100%;
      padding: 2rem;
      background: red;
      transition: translate 0.5s;
    }
    
    #navbar.is-hidden {
      translate: 0 -101%;
    }
    <div>Some other DIV at the top of my page</div>
    
    <nav id="navbar">Hello NAVBAR</nav>
    
    <main>
      Hello. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati veritatis quaerat, cumque asperiores cum repudiandae vel minus, ab earum voluptatem. Possimus, adipisci laborum itaque perferendis reiciendis, impedit corrupti odio officia
      <div style="height: 200vh">...</div>
      End.
    </main>

    To change the trigger height point in which the navbar initially hides, change to i.e: elNav.offsetHeight / 2 or any other value.

    To conclude
    the above example does not necessitates to set any static heights, to use any placeholders, and works pretty good on any website that needs to show the navigation as soon as the user starts to scroll up, with the addition to show the navigation bar at the far end (scrolled to bottom) — without much heavyweight coding.
    For a similar solution, as reference see: Hide nav bar when user stops scrolling

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search