[JS30] - 24) Sticky Nav

approach 1

처음에는 이렇게 접근했다.

  const nav = document.querySelector('#main');
  console.log(nav)
  document.addEventListener('scroll', handleStickyNav);


  function handleStickyNav() {
    if(nav.offsetTop < window.scrollY) {
      console.log('change to sticky nav!')
      nav.classList.add('nav-sticky')
    } else {
      nav.classList.remove('nav-sticky');
    }
  }

css 'nav-sticky'는 position: fixed;를 가지고 있다.
이 클래스를 추가해줌으로써 nav의 position을 relative에서 fixed로 바꾸어주어 스크롤할 때 함께 따라올 수 있도록 했다(아래 gif참고)

한 가지 간과했던 게 있었다.
console.log(nav.offsetTop)을 했을 때 출력결과와 함께 화면을 보자.

위와 같이 처음 네비게이션 바가 sticky하게 바뀌긴 했지만
다시 위로 스크롤했을 때 이미 위로 fix된 nav bar의 offsetTop을 기준으로 scrollY보다 클 때 적용했던 nav-sticky 클래스가 제거 되면서 기존에 있던 위치가 아닌 맨 위에 도달했을 때에서야 제자리로 돌아가게 된다.
즉, nav의 포지션이 바뀌면서 offsetTop이 기존의 nav값이 아닌 0으로 초기화되어 제대로 작동하지 않았다.

approach 2

이를 위해 nav.offsetTop의 초기 값을 별도의 변수에 할당해준 뒤 상수처럼 사용했다.


  let navTop = nav.offsetTop; //변수 지정

  function handleStickyNav() {
    if(navTop< window.scrollY) { //상수값으로 사용
      nav.classList.add('nav-sticky')
    } else {
      nav.classList.remove('nav-sticky');
    }
    console.log(nav.offsetTop)
  }

nav값이 스크롤을 다시 위로 올릴때 제대로 제자리에 돌아가는 것을 확인할 수 있다.

하지만 여전히 한 가지 문제가 있는데, 위gif에서 확인할 수 있듯이 nav bar가 sticky하게 바뀌는 타이밍이 부드럽게 연결되지 않고 뚝뚝 끊기는 느낌이 든다.

approach 3

nav가 sticky하게 바뀌기전

sticky하게 바뀐 직후 이다.

해당 영역에 있는 margin과 padding값 때문인 듯 하다. 자세히 알아보자.

approach 4

알아냈다!

위 이미지와 같이, nav bar가 sticky로 바뀌면서 document의 다른 요소들과는 독립적으로 위쪽에 고정되기 때문에 그 면적이 빠진 공백만큼 nav의 아래 요소가 위로 딸려올라오는 것이 이유였다.

그렇다면 그만큼의 높이를 navbar의 position이 fixed로 바뀔 때 추가해주면 된다.

  function handleStickyNav() {
    if(navTop< window.scrollY) {
      nav.classList.add('nav-sticky');
      document.body.style.paddingTop = nav.offsetHeight + 'px';//높이 추가
    } else {
      nav.classList.remove('nav-sticky');
      document.body.style.paddingTop = 0;//높이 제거
    }
  }

자연스럽고 부드럽게 동작하는 것을 볼 수 있다!

Reference

좋은 웹페이지 즐겨찾기