대부분의 마우스 입력 장치에는 휠(wheel)을 지원한다. 보통 이 휠을 이용하여 화면을 스크롤하는데 이러한 방식으로 화면 단위로 스크롤시키는 기본적인 개념을 알아보자.
화면 단위 이동을 위해서는 다음의 사항을 체크해야 한다.
헤더(<header>
)의 내비게이션 구현, 메인(<main>
)의 콘텐츠를 화면 단위로 구성하기 위해 다음의 마크업 구조를 추전한다.
<header class="header">
<ul>
<li><code class="language-html">Section 1</code></li>
<li><code class="language-html">Section 2</code></li>
<li><code class="language-html">Section 3</code></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>©2021</p>
</footer>
영역은 뷰포트에 고정하며 각 <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
)로 제공한다. 방향에 따라 음수와 양수로 나누어지므로 이 값을 이용하여 화면 스크롤 방향을 분기할 수 있다.
<ul>
요소와 화면 단위의 <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);
});
});
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"
});
}
[Test in Live Code Editor] 메뉴를 선택해 새 창으로 에디터를 열어 테스트한다.