admin管理员组

文章数量:1401776

I have a header that I'd like to turn into a sticky header once the user starts scrolling down the page, it should also be smooth and not just jump down the screen and I don't want to just use a position: fixed to just stick it to the top of the screen. This is also in a nextjs application.

const Header = () => {
  useEffect(() => {
    window.onscroll = () => {
      document.getElementById('header').classList.add('sticky')

      // what else do I need here
    }
  }, [])
}

...

#header {
  transition: top 1s;
}

#header.sticky {
  position: sticky;

  // what else do I need here
}

I have a header that I'd like to turn into a sticky header once the user starts scrolling down the page, it should also be smooth and not just jump down the screen and I don't want to just use a position: fixed to just stick it to the top of the screen. This is also in a nextjs application.

const Header = () => {
  useEffect(() => {
    window.onscroll = () => {
      document.getElementById('header').classList.add('sticky')

      // what else do I need here
    }
  }, [])
}

...

#header {
  transition: top 1s;
}

#header.sticky {
  position: sticky;

  // what else do I need here
}
Share Improve this question edited Nov 3, 2021 at 11:39 asked Aug 4, 2021 at 12:17 user16435030user16435030 1
  • with position sticky, you don't need to add the class - you should just start with it and it will stick when it scrolls past the point you want it to stick - developer.mozilla/en-US/docs/Web/CSS/position – Pete Commented Aug 4, 2021 at 12:20
Add a ment  | 

2 Answers 2

Reset to default 4

There's a couple of things you'll need to do it.

let timeout
let scroll = 0

const Header = () => {
  useEffect(() => {
    window.onscroll = () => {
      if (timeout) {
        clearTimeout(timeout)
      }

      timeout = setTimeout(() => {
        if (scroll >= window.scrollY && window.scrollY > 10) {
          document.getElementById('header').classList.add('sticky')
        } else {
          document.getElementById('header').classList.remove('sticky')
        }

        scroll = window.scrollY
      }, 10)
    }
  }, [])
}

...

#header {
  top: -100px;
  transition: top 0.5s ease-in-out;
}

#header.sticky {
  position: sticky;
  top: 0;
}
  • Create a window event listener on scroll, use useEffect if it's a server side rendered application like in nextjs, otherwise you can leave that.
  • Assign or remove the sticky class on scroll, you can do this with document.getElementById or by using useRef on the header ponent.
  • Use a timeout so that the event isn't fired on every single scroll, instead it should fire only 10ms after the scrolling stopped.
  • Keep track of the scroll variable so that you can figure out if the user is scrolling up or down, that way you can display the header only if they're scrolling up.
  • As a little trick you can set the initial header position top to -100px, which will have no effect if there isn't actually any position: absolute, position: fixed or position: sticky on the header. Then when you apply the class sticky you change the top value to 0, which will create an effect where the header is suddenly "appearing" from the top once you scroll down. This is what's creating the animation.

The self-answered solution seems like so much more work than is necessary; a pure CSS solution should be sufficient, unless I'm misunderstanding the requirements. See below:

const Header = () => {
  return (
    <div className="header">header content here</div>
  );
};


const Content = () => {
  return (
    <div className="content">
      <h1>Hello</h1>
      <p>How are you?</p>
      <p>Lovely weather were having, no?</p>
      <p>The quick brown fox jumped over the lazy dog</p>
      <p>Every Good Boy Does Fine</p>
      <p>Mary's violet eyes made john stay up nights proposing</p>
      <p>FOIL</p>
      <p>How are you?</p>
      <p>Lovely weather were having, no?</p>
      <p>The quick brown fox jumped over the lazy dog</p>
      <p>Every Good Boy Does Fine</p>
      <p>Mary's violet eyes made john stay up nights proposing</p>
      <p>FOIL</p>
      <p>How are you?</p>
      <p>Lovely weather were having, no?</p>
      <p>The quick brown fox jumped over the lazy dog</p>
      <p>Every Good Boy Does Fine</p>
      <p>Mary's violet eyes made john stay up nights proposing</p>
      <p>FOIL</p>
    </div>
  );
};

const App = () => {
  return (
    <div>
      <Header />
      <Content />
    </div>
  );
};

// Render it
ReactDOM.render(
  <App />,
  document.getElementById("react")
);
body {
  padding: 0;
  margin: 0;
}

.header {
  background-color: pink;
  padding: 1rem;
  position: sticky;
  top: 0;
}
<script src="https://cdnjs.cloudflare./ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

本文标签: javascriptHow to create an animated smooth sticky header in reactStack Overflow