내 블로그의 Topbar와 같이 화면을 스크롤 해도 항상 그 자리에 고정돼 있는 Topbar를 구현하자. 내 블로그의 Fixed Topbar는 Fixed Topbar 구현 포스트의 방법2 를 바탕으로 제작되었다. 이 포스트에서는 같은 방법을 Minimal-Mistakes 테마에 적용하는 과정을 포스팅 할 것이다.

과정https://innolifes22.github.io/blog/topbar/#과정

과정을 진행하면서 Topbar를 페이지 최상위에 고정 시키고 Fixed Topbar 구현 포스트에서 제기했던 HTML 요소가 가려지는 문제를 해결할 것이다.

1. Topbar 고정https://innolifes22.github.io/blog/topbar/#1-topbar-고정

mmistakes 테마에서 Topbar를 페이지 최상위에 고정시키기위해 아래와 같은 CSS 를 적용한다.

1
2
3
4
5
6
.masthead {
  position: fixed;
  top: 0;
  height: calc(3 * 16px);
  width: 100%;
}

코드의 4번째 줄에서 Topbar의 높이 calc(3 * 16px);는 48px가 된다.

2. 내용 여백 조정https://innolifes22.github.io/blog/topbar/#2-내용-여백-조정

Fixed Topbar로 인해 포스트 내용이 가려지는 것을 방지하기 위해 내용이 약간 아래부터 시작하도록 윗쪽 여백을 넣는다.

1
2
3
body {
  padding-top: calc(3 * 16px + 8px);
}

Fixed Topbar의 높이(3*16px=48px)에 +8px 만큼의 여백을 더 추가하였다.

3. Javascript 작성https://innolifes22.github.io/blog/topbar/#3-javascript-작성

위 두가지 css 설정으로 해결 되지 않는 문제들을 javascript를 이용해서 해결한다.
Fixed Topbar 구현 포스트에서 제기한 문제 상황 2, 3이 여기에 해당한다.

스크롤 목적지를 살짝 위로 설정https://innolifes22.github.io/blog/topbar/#스크롤-목적지를-살짝-위로-설정

먼저 페이지를 스크롤하는 함수를 정의한다.

1
2
3
4
5
6
top_offset = 99;
function scrollToHash(h) {
  // 스크롤 위치를 목적지의 y 좌표 보다 top_offset 만큼 위의 좌표로 계산
  var yPos = $(h).offset().top - top_offset;
  scrollTo({top: yPos, behavior: 'smooth'});
}

자동 스크롤을 하면 기본적으로 브라우저 화면 맨 꼭대기에 스크롤 목적지의 y좌표가 위치하도록 스크롤 된다. 이때 스크롤 목적지의 y좌표에 top_offset 만큼을 빼주면 브라우저 화면 맨 꼭대기에 top_offset 픽셀 만큼 위의 y좌표가 오게된다.
즉, 실제 목적지는 브라우저 화면 꼭대기에서 부터 top_offset 만큼 아래에 있도록 스크롤 된다.
또한 scrollTo()(스크롤 함수)에 behavior: 'smooth' 옵션을 넣어서 부드러운 스크롤링을 설정했다.

Windows에서 애니메이션 표시https://innolifes22.github.io/blog/topbar/#windows--

참고로 Windows OS에서 부드러운 스크롤링은 Windows에서 애니메이션 표시 옵션을 켜야 정상적으로 동작 한다.

다른 페이지로 부터 이동해 온 다음 특정 위치로 자동 스크롤https://innolifes22.github.io/blog/topbar/#다른-페이지로-부터-이동해-온-다음-특정-위치로-자동-스크롤

다른 페이지에서 링크를 클릭하면 링크의 href 경로로 페이지 이동한다. 이때 hrefhash1가 있으면 브라우저는 페이지 이동한 후 해당 hash의 위치로 화면을 자동 스크롤 한다.

1
2
3
4
5
6
$(function() {
  if(location.hash.length > 0) {
    var h = decodeURIComponent(location.hash);
    scrollToHash(h);
  }
});

$(function() { }); 로 시작하는 함수는 jquery에서 지원하는 $( document ).ready(function() { }); 함수의 축약형이다. 이 함수는 페이지의 로드가 완료되면 실행 된다는 특징이 있다.
이 함수를 이용해서 위와 같이 코드를 짜면 페이지 로드가 완료되었을 때 현재 URL에 hash가 포함되어 있는지 확인하고 hash가 포함돼 있다면 해당 hash의 y 좌표로 스크롤 한다.

같은 페이지 내에서 다른 위치로 자동 스크롤https://innolifes22.github.io/blog/topbar/#같은-페이지-내에서-다른-위치로-자동-스크롤

링크를 클릭하면 링크의 href 경로로 이동하는데 그 경로가 현재 페이지의 주소와 같은 경우 페이지의 이동 없이 href에 있는 hash의 위치로 자동 스크롤 한다.

1
2
3
4
5
6
7
8
9
$('a').click(function (e) {
  if($(this)[0].origin == location.origin &&
     $(this)[0].pathname == location.pathname) {
    e.preventDefault();
    var h = $(this).attr('href');
    scrollToHash(h);
    history.pushState({}, null, h);
  }
});

링크의 href를 이용하므로 <a> 태그에서만 동작한다. 다른 태그에서도 같은 스크롤 기능을 구현 하려면 $('a') 부분을 변경해 주면 된다.
두번째 줄에 있는 조건문의 origin은 URL의 root 주소를 의미한다. 따라서 이동하려는 목적지와 현재 페이지의 root 주소가 같은지 확인 할 수 있다. 내 블로그의 root 주소는 https://seungwubaek.github.io가 된다.
이어서 세번째 줄의 pathname은 root 주소 이후로 이어지는 주소를 의미한다. 여기까지는 hash가 포함되지 않는다.
즉, 조건문의 참이 되는 주소는 이동하려는 목적 주소가 현재 페이지와 같은 주소이다. e.preventDefault();를 이용해 기본으로 설정되어 있는 자동 스크롤 기능을 해제한다.
그리고 링크가 가진 hash 값을 인자로 하는 스크롤 함수(scrollToHash)를 실행시킨다.
마지막으로 history.pushState 함수로 href가 가진 hash 값을 이동한 곳에 맞게 변경해준다.

historyhttps://innolifes22.github.io/blog/topbar/#history

history라는 객체는 페이지 이동 히스토리를 저장하고 있다. 브라우저의 뒤로/앞으로 가기 기능은 이 객체가 있기 때문에 가능하다. 그래서 위 코드와 같이 history.pushState 를 해주면 historyhash를 포함하는 href가 저장되고 뒤로/앞으로 가기 기능을 그대로 사용할 수 있다.

Javascript 전체 코드https://innolifes22.github.io/blog/topbar/#javascript-전체-코드

위 코드 조각들을 한번에 쓰면 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$(function() {
  top_offset = 99;
  function scrollToHash(h) {
    var yPos = $(h).offset().top - top_offset;
    scrollTo({top: yPos, behavior: 'smooth'});
  }
  // 외부 페이지로부터 이동해 온 후 다른 위치로 스크롤 할 때
  if(location.hash.length > 0) {
    var h = decodeURIComponent(location.hash);
      scrollToHash(h);
  }
  // 같은 페이지에서 다른 위치로 스크롤 할 때
  $('a').click(function (e) {
    if($(this)[0].origin == location.origin &&
       $(this)[0].pathname == location.pathname) {
      e.preventDefault();
      var h = $(this).attr('href');
      scrollToHash(h);
      history.pushState({}, null, h);
    }
  });
});
  1. hash: href 끝에 #으로 시작하는 문자열. 요소의 id를 의미. 

Meta Info

Categories:

Published At:

Modified At:

Leave a comment