본문으로 바로가기

fixed header on scroll

category Web Tech/jQuery 2016. 1. 11. 08:40

스크롤시 헤더 보이거나 숨기기

사용자의 스크롤을 감지하여 원하는 요소에 동작을 추가하는 것으로 일반적으로 상단의 네비게이션에 자주 이용되고 있습니다.

기존의 고정(Fixed)된 네비게이션이 차지하는 화면의 비율을 없애고 사용자의 반응에 따라 네비게이션이 등장함으로써 좀 더 유연하게 화면의 가시영역을 확보할 수 있습니다.

이러한 UI를 sticky, spy, floating (sticky header, sticky tab, floating menu, spy tab...)등으로 불려지고 있으니 참고하기 바랍니다.




고정된 헤더(네비게이션) 사용성 부족

많은 웹사이트에서 네비게이션 탐색에 도움을 주기위해 상단의 헤더(네비게이션을 포함한)를 CSS의 포지셔닝을 사용해 position: fixed 와 같이 고정해 두곤 합니다. 

헤더 부분은 대부분 상호(브랜드)를 포함하고 네비게이션을 포함하기에 고정된 헤더에 높이가 긴 콘텐츠를 포함하고 있는 경우 오히려 사이트의 사용자 경험(UX)을 떨어뜨리는 요인이 되기도 합니다. 

이는 모바일과 같은 뷰포트가 작은 기기들에서는 더욱 그러합니다. 

기존의 단순히 고정된 형태의 헤더 디자인을 제공하는 것 보다는 사용자의 스크롤 방향에 따라 헤더부분을 보여주거나 감춤으로써, 사용자의 의도에 맞는 디자인을 제공하는 것이 목적입니다. 

즉, 사용자의 스크롤이 아래로 향한다면 콘텐츠를 탐색하길 원하는 것이라 간주하고 헤더부분을 감추고, 스크롤이 위로 향한다면 처음으로 돌아가거나 네비게이션을 찾아 이동하는 것으로 간주하여 헤더부분을 재등장 시키는 원리입니다.




원리의 이해

CSS3의 트랜지션과 약간의 자바스크립트를 사용하여 이 효과를 얻는게 주된 원리입니다.

  1. 헤더 요소에 position: fixed 를 설정합니다. 
  2. 스크롤 방향이 아래로 향한다면 헤더 요소에 클래스를 추가하고 이 클래스에 의해 헤더가 위로 사라지게 됩니다. 
  3. 스크롤 방향이 위로 향한다면 추가한 클래스를 제거하여 헤더 요소가 재등장하도록 합니다.



HTML 구조

기본 구조는 아래와 같으나 사실 헤더부분은 fixed 값을 가지게 되므로 다른 곳의 영향을 벗어나기에 어떠한 구조라도 상관 없습니다.

html
<header></header>
<main></main>
<footer></footer>



CSS 예제

기본적인 CSS 디자인은 아래와 같으며, 사용자의 디자인에 적합하게 수정하면 됩니다.

css
body {
    padding-top: 40px; // 헤더 높이만큼 여백부여
}

header {
    position: fixed;
    top: 0;
    left: 0
    width: 100%;
    height: 40px;
    background: #f5b335;
    transition: top 0.2s ease-in-out;
}

// 자바스크립트로 추가될 클래스
.nav-up {
    top: -40px; // 헤더 높이와 같게 
}

예제는 위와 같으나 부드러운 효과를 부여하기 위해서는 각종 애니메이션을 적용할 수도 있습니다. 

또한 단순히 트랜지션으로 위치 이동을 제어하는 것보다 트랜스폼(transform)과 트랜지션의 조합이 다양한 기기에서 버벅임없는 자연스러운 효과를 얻을 수 있을 것입니다.

하지만 크로스브라우징을 고려한다면 jQuery를 이용하여 보다 손쉽게 적용할 수 있을 것입니다.




javaScript 구현

jQuery를 문서에 삽입하도록 합니다.

html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

코드를 구현하기에 앞서, 스크롤 이벤트를 감지하고 동작을 부여하는 것은 성능에 많은 영향을 준다는 것을 인지해야 합니다. 

이 문제를 해결하기 위해서 스크롤된 모든 픽셀에 대해 동작을 구현하는 것이 아니라 사용자가 스크롤한 간격을 확인하도록 하여 좀 더 성능을 최적화시킬 수 있습니다.

javascript
var didScroll;
// 스크롤시에 사용자가 스크롤했다는 것을 알림 
$(window).scroll(function(event){
    didScroll = true;
});

// hasScrolled()를 실행하고 didScroll 상태를 재설정
setInterval(function() {
    if (didScroll) {
        hasScrolled();
        didScroll = false;
    }
}, 250);

function hasScrolled() {
  // 동작을 구현
}

$(window).scroll 에 의해 스크롤 이벤트를 감지하여 didScroll 의 변수 값을 true로 설정합니다.

매 250ms 마다 didScroll의 변수 값을 체크하여 동작을 구현하고 다시 didScroll의 변수 값을 false로 설정합니다. 

이는 스크롤될때 마다 전체의 동작을 구현하는 것보다 변수를 설정하는 것이 브라우저의 부하를 줄일 수 있는 방법이 됩니다.



header(헤더) 숨기기

아래의 요구사항이 충족될 때 헤더를 숨기도록 합니다.

  • delta 값 보다 더 스크롤이 되었을 경우 
  • 헤더의 높이보다 더 스크롤이 되었을 경우 
  • 위 또는 아래로 스크롤이 되었을 경우 
  • 변수에 현재의 스크롤 위치를 저장



변수값 설정

스크립트의 상단에 변수값을 설정합니다.

javascript
var lastScrollTop = 0;
var delta = 5;  // 동작의 구현이 시작되는 위치 
var navbarHeight = $(‘header’).outerHeight();  // 영향을 받을 요소를 선택



hasScrolled() 구현

javascript
// 접근하기 쉽게 현재 스크롤의 위치를 저장한다.
var st = $(this).scrollTop();

// 설정한 delta 값보다 더 스크롤되었는지를 확인한다.
if (Math.abs(lastScrollTop — st) <= delta)
    return;

// 헤더의 높이보다 더 스크롤되었는지 확인하고 스크롤의 방향이 위인지 아래인지를 확인한다.
// If current position > last position AND scrolled past navbar...
if (st > lastScrollTop && st > navbarHeight){
    // Scroll Down
    $(‘header’).removeClass(‘nav-down’).addClass(‘nav-up’);
} else {
    // Scroll Up
    // If did not scroll past the document (possible on mac)...
    if(st + $(window).height() < $(document).height()) { 
      $(‘header’).removeClass(‘nav-up’).addClass(‘nav-down’);
    }
}

// lastScrollTop 에 현재 스크롤위치를 지정한다.
lastScrollTop = st;





완성된 DEMO VIEW

See the Pen fixed header on Scroll by jaeheekim (@jaehee) on CodePen.



Jaehee's WebClub