最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - JS Showhide header on scroll effect - but only after the header has scrolled up and out of window - Stack Overflow

programmeradmin5浏览0评论

I have some simple Javascript. When scrolling down the header disappears. When scrolling up the header appears. This all works fine:

var prevScrollpos = window.pageYOffset;
window.onscroll = function() {
  var currentScrollPos = window.pageYOffset;
  if (prevScrollpos > currentScrollPos) {
    document.querySelector("header").style.top = "0";
  } else {
     document.querySelector("header").style.top = "-7.2rem";
  }
  prevScrollpos = currentScrollPos;
}




header {
    background-color: rgb(255, 255, 255);
    height: 7.2rem;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    transition: top 0.2s ease-in-out;
    z-index: 100;
}

However, when the page is at the top of the window, and the user scrolls down, even by 1px, the header disappears, leaving a great big blank space where the header used to be. Is it possible that this show / hide on scroll script only starts once the header has disappeared off the top of the browser window? i.e. the effect only kicks in after the height of the header has been scrolled (so that the user doesn't see the empty white space) i.e. the header is not fixed, but relative. It scrolls up and out of the window. Then the effect starts: scroll down = no header / scroll up = header is fixed at the top of the window.

I have some simple Javascript. When scrolling down the header disappears. When scrolling up the header appears. This all works fine:

var prevScrollpos = window.pageYOffset;
window.onscroll = function() {
  var currentScrollPos = window.pageYOffset;
  if (prevScrollpos > currentScrollPos) {
    document.querySelector("header").style.top = "0";
  } else {
     document.querySelector("header").style.top = "-7.2rem";
  }
  prevScrollpos = currentScrollPos;
}




header {
    background-color: rgb(255, 255, 255);
    height: 7.2rem;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    transition: top 0.2s ease-in-out;
    z-index: 100;
}

However, when the page is at the top of the window, and the user scrolls down, even by 1px, the header disappears, leaving a great big blank space where the header used to be. Is it possible that this show / hide on scroll script only starts once the header has disappeared off the top of the browser window? i.e. the effect only kicks in after the height of the header has been scrolled (so that the user doesn't see the empty white space) i.e. the header is not fixed, but relative. It scrolls up and out of the window. Then the effect starts: scroll down = no header / scroll up = header is fixed at the top of the window.

Share Improve this question asked Sep 15, 2020 at 13:07 user2991837user2991837 7962 gold badges9 silver badges22 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 11

There are 2 ways you can do this, depending on what behaviour you would like. In both cases we want to get the header element and it's position:

var headerDiv = document.querySelector("header");
var headerBottom = headerDiv.offsetTop + headerDiv.offsetHeight;

This means that in the scroll, we can check if we have passed the header:

    if (window.pageYOffset >= headerBottom)

1: Header scrolls out of view as normal, Fixed to top on scrolling up

In this version, the header scrolls out of view when scrolling down, but when you start to scroll up it will appear fixed to the top of the screen.

Full Working Example:

var prevScrollpos = window.pageYOffset;

/* Get the header element and it's position */
var headerDiv = document.querySelector("header");
var headerBottom = headerDiv.offsetTop + headerDiv.offsetHeight;

window.onscroll = function() {
  var currentScrollPos = window.pageYOffset;

  /* if scrolling down, let it scroll out of view as normal */
  if (prevScrollpos <= currentScrollPos ){
      headerDiv.classList.remove("fixedToTop");
      headerDiv.style.top ="-7.2rem";
  }
  /* otherwise if we're scrolling up, fix the nav to the top */
  else{  
      headerDiv.classList.add("fixedToTop");
      headerDiv.style.top = "0";
  }

  prevScrollpos = currentScrollPos;
}
body{ margin: 0;}
header {
    background: blue;
    height: 7.2rem;
    transition: all 0.2s ease-in-out;
    z-index: 100;
}

.content { 
    height:1000px; 
}

header.fixedToTop {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
}

/* add space for fixed header when it's fixed to top */
header.fixedToTop + .content{
    margin-top:8rem;
}
<header></header>
<div class="content" id="contentdiv">
<h1>My Page</h1>
<p>Content 1</p><p>Content 2</p><p>Content 3</p><p>Content 4</p><p>Content 5</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
</div>

How This Works

We need to remove the fixed positioning from the header and add it to a class (e.g. fixedToTop) that we will apply on scrolling:

header {
    height: 7.2rem;
    transition: all 0.2s ease-in-out;
    z-index: 100;
}
header.fixedToTop {
    position: fixed;
    top: 0; left: 0; right: 0;
}

Now the logic for our scroll function is very simple:

  1. If we're scrolling down then let the header scroll out of view - remove the fixedToTop class.
  2. If we are scrolling up, add our fixedToTop class which will make it appear

Note, we need to explicitly set the value for top to make the transition animation to work, so we do that in the code also.

Putting this together, we get the following scroll function:

window.onscroll = function() {
  var currentScrollPos = window.pageYOffset;

  /* if scrolling down, let it scroll out of view as normal */
  if (prevScrollpos <= currentScrollPos ){
      headerDiv.classList.remove("fixedToTop");
      headerDiv.style.top ="-7.2rem";
  }
  /* otherwise if we're scrolling up, fix the nav to the top */
  else{  
      headerDiv.classList.add("fixedToTop");
      headerDiv.style.top = "0";
  }

  prevScrollpos = currentScrollPos;
}

2: Header is fixed until we scroll passed where it would normally have disappeared; Fixed to top on on scrolling up

In this case the header is fixed until we scroll passed it's "natural" position where it would disappear.

Working Example:

var prevScrollpos = window.pageYOffset;

/* Get the header element and it's position */
var headerDiv = document.querySelector("header");
var headerBottom = headerDiv.offsetTop + headerDiv.offsetHeight;

window.onscroll = function() {
  var currentScrollPos = window.pageYOffset;

  /* if we're scrolling up, or we haven't passed the header,
     show the header at the top */
  if (prevScrollpos > currentScrollPos  || currentScrollPos < headerBottom){  
      headerDiv.style.top = "0";
  }
  else{
      /* otherwise we're scrolling down & have passed the header so hide it */
      headerDiv.style.top = "-7.2rem";
  } 

  prevScrollpos = currentScrollPos;
}
header {
    background: blue;
    height: 7.2rem;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    transition: top 0.2s ease-in-out;
    z-index: 100;
}

.content { 
    height:1000px; 
    margin-top:8rem; /* add space for fixed header */
}
<header></header>
<div class="content" id="contentdiv">
<h1>My Page</h1>
<p>Content 1</p><p>Content 2</p><p>Content 3</p><p>Content 4</p><p>Content 5</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
</div>

How This Works

The logic in your scroll function is like this:

  1. If we're scrolling up, then show the header:
  2. If we are scrolling down...
  3. ...if we've scrolled passed the header, hide it
  4. ... otherwise show it

Putting this together, we get the following scroll function:


var prevScrollpos = window.pageYOffset; // save the current position

window.onscroll = function() {
   var currentScrollPos = window.pageYOffset;

  /* if we're scrolling up, or we haven't passed the header, show the header */
  if (prevScrollpos > currentScrollPos  || currentScrollPos < headerBottom){  
      headerDiv.style.top = "0";
  }
  else{
      /* otherwise we're scrolling down & have passed the header so hide it */
      headerDiv.style.top = "-7.2rem";
  } 

  prevScrollpos = currentScrollPos;
}

Perhaps you can just pare the scroll position with the height of the element:

var prevScrollpos = window.pageYOffset;
window.onscroll = function() {
   var currentScrollPos = window.pageYOffset;
   if (prevScrollpos > currentScrollPos) {
     document.querySelector("header").style.top = "0";
   } else if (currentScrollPos > document.querySelector("header").offsetHeight) {
     document.querySelector("header").style.top = "-7.2rem";
   }
   prevScrollpos = currentScrollPos;
}

header {
    background-color: rgb(255, 255, 255);
    height: 7.2rem;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    transition: top 0.2s ease-in-out;
    z-index: 100;
}

I used the first answer provided by FluffyKitten and it worked well. Thank you. I would have mented there, but I lack the reputation to do so.

To help others, while implementing FluffyKitten's first answer, I learned that the vertical alignment of the header and .content varied slightly between (a) load or refresh (no scrolling yet on page so not fixedToTop) versus (b) fixedToTop after scrolling because only the body margins were set to 0.

I not only set the body element margin to 0 (as FluffyKitten does), but also had to set the top margin on the header and on the .content element to 0 to prevent minor vertical layout discrepancies between when my webpages were first loaded or refreshed (when header is not fixedToTop) versus when the header is fixedToTop after scrolling up.

export function Header() {

const [prevScrollPos, setPrevScrollPos] = useState(0);

const [headerFixed, setHeaderFixed] = useState(false);

useEffect(() => {
  const handleScroll = () => {
    const currentScrollPos = window.pageYOffset;

    if (currentScrollPos < 100) {
      console.log(currentScrollPos);
      setHeaderFixed(false);
    } else if (prevScrollPos <= currentScrollPos) {
      setHeaderFixed(false);
    } else {
      setHeaderFixed(true);
    }

    setPrevScrollPos(currentScrollPos);
  };

  window.addEventListener("scroll", handleScroll);

  return () => {
    window.removeEventListener("scroll", handleScroll);
  };
}, [prevScrollPos]);

return
   <header className={`sticky transition-all duration-300 z-50 ${headerFixed
       ? " top-0 left-0 right-0 bg-white shadow-md"
       : "bg-transparent"}`}>
     <div>hjasdkjas</div>
   </header>

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论