WEB-DEVELOPMENT

  • account_tree
  • bug_report

휠(wheel)을 이용한 화면 단위 이동

대부분의 마우스 입력 장치에는 휠(wheel)을 지원한다. 보통 이 휠을 이용하여 화면을 스크롤하는데 이러한 방식으로 화면 단위로 스크롤시키는 기본적인 개념을 알아보자.

화면 단위 이동을 위한 체크 리스트

화면 단위 이동을 위해서는 다음의 사항을 체크해야 한다.

  • 화면 단위의 콘텐츠 구성을 위한 마크업 설계 필요
  • 화면 단위 스크롤은 다음의 실행을 통해 이루어지므로 적절한 이벤트 등록과 처리 필요
    • 내비게이션에서 메뉴를 클릭시
    • 마우스의 휠(wheel)을 돌릴 경우
    • 마우스로 직접 스크롤바를 드래그 하는 경우는 제외(스크롤바 숨김)

마크업 설계와 스타일링

헤더(header)의 내비게이션 구현, 메인(main)의 콘텐츠를 화면 단위로 구성하기 위해 다음의 마크업 구조를 추전한다.

<header class="header">
  <ul>
    <li>Section 1</li>
    <li>Section 2</li>
    <li>Section 3</li>
  </ul>
</header>

<main class="main">
  <section>
    <h2>Section 1 title</h2>
    <p>Section contents</p>
  </section>
  <section>
    <h2>Section 2 title</h2>
    <p>Section contents</p>
  </section>
  <section>
    <h2>Section 3 title</h2>
    <p>Section contents</p>
  </section>  
</main>

<footer class="footer">
  <p>&copy;2021</p>
</footer>

<header> 영역은 뷰포트에 고정하며 각 <section> 영역의 높이를 뷰포트의 높이로 설정한다. 화면 단위로 이동하여 콘텐츠를 보여주는 경우에는 스크롤바는 불필요하다.

body {
  margin: 0;
  overflow: hidden;
}
.header {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  height: 50px;
  background: rgba(0, 0, 0, 0.7);
}
.header > ul {
  list-style: none;  
  margin: 0;
  padding-left: 0;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0 30px;
}

.main > section {
  min-height: 100vh;
  padding-top: 70px;
}

.footer {
  background: #CCC;
  overflow: hidden;
}

스크롤 이벤트

화면 단위 스크롤은 내비게이션과 마우스의 휠(wheel)을 이용한다. 이 두가지 경우 모두 현재 화면에 보여지는 section에 대한 인덱스(indxe)를 활용하여 대상 요소를 판단한다.

내비게이션의 경우는 메뉴별 클릭시 메뉴 항목(<li>)의 인덱스로 활성 <section>의 인덱스로 사용한다.

마우스의 휠(wheel)의 경우는 wheel 이벤트 타입으로 이벤트를 등록하며 이벤트 발생시 활성 인덱스를 가감하는 방식으로 계산한다. 주의할 점은 휠 동작에 대한 이벤트는 휠을 돌리는 동작이 멈출때까지 지속되어 발생한다. 따라서 휠을 돌리는 동작이 끝날 때 화면을 이동시키는 처리를 해야 한다. setTimeout() 메소드를 활용하면 쉽게 해결할 수 있다.

또한 마우스의 휠(wheel)을 돌리는 방향에 따라 화면 위와 아래 방향으로 이동시켜야 한다. 휠 이벤트 객체를 통해 방향을 분기할 수 있는데 휠을 돌릴때 휠 동작의 강도에 따라 number 타입으로 데이터를 deltaY 프로퍼티(수평의 경우 deltaX)로 제공한다. 방향에 따라 음수와 양수로 나누어지므로 이 값을 이용하여 화면 스크롤 방향을 분기할 수 있다.

내비게이션 이벤트 등록과 화면 단위의 <section> 요소 준비
let elNavi = document.querySelector(".header > ul");
let aElSection = document.querySelectorAll(".main > section");
let curSIdx = 0;
내비게이션 메뉴 이벤트 등록
Array.from(elNavi.children, function(elMenu, idx, elMenus) {
  elMenu.addEventListener("click", function() {
   	doScroll(idx);
  });
});
휠(wheel) 이벤트 등록
let wheelTimer;
window.addEventListener("wheel", function(e) {
  clearTimeout(wheelTimer);
  wheelTimer = setTimeout(function() {
  	if(e.deltaY < 0) 	doScroll(++curSIdx);
    else doScroll(--curSIdx);
  }, 50);
});
스크롤 처리 함수 준비
function doScroll(sidx) {
  console.log(sidx);
  sidx = sidx < 0 ? 0 : sidx;
  sidx = sidx > aElSection.length - 1 ? aElSection.length - 1 : sidx;
    
  curSIdx = sidx;
    
  aElSection[curSIdx].scrollIntoView({
    block: "start", inline: "start", behavior: "smooth"
  });  	
}
완성 샘플 코드