
마우스 휠을 내리면 섹션 하나 내려가고, 올리면 섹션 하나 올라가도록 구현
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>scroll</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
overflow: hidden;
}
.top_menu {
position: fixed;
top: 1rem;
right: 1rem;
display: flex;
gap: 1rem;
transform: translateY(calc(-100% - 1rem));
transition: transform 0.8s;
}
.top_menu a {
padding: 1rem;
text-decoration: none;
color: white;
background-color: black;
}
.top_menu.on {
transform: translateY(0);
}
.top_menu a:hover,
.top_menu a:active,
.top_menu a.on {
background-color: white !important;
color: black;
}
.goTop {
position: fixed;
right: 100px;
bottom: 100px;
background-color: antiquewhite;
padding: 1rem;
}
.sec_con section {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
#sec1 {
background-color: tomato;
}
#sec2 {
background-color: teal;
}
#sec3 {
background-color: antiquewhite;
}
#sec4 {
background-color: aliceblue;
}
#sec5 {
background-color: beige;
}
</style>
</head>
<body>
<nav class="top_menu">
<a href="#sec1">1번영역</a>
<a href="#sec2">2번영역</a>
<a href="#sec3">3번영역</a>
<a href="#sec4">4번영역</a>
<a href="#sec5">5번영역</a>
</nav>
<a href="#sec1" class="goTop">상단으로</a>
<main class="sec_con">
<section id="sec1">1번 섹션</section>
<section id="sec2">2번 섹션</section>
<section id="sec3">3번 섹션</section>
<section id="sec4">4번 섹션</section>
<section id="sec5">5번 섹션</section>
</main>
<script>
const $sections = [...document.querySelectorAll('.sec_con > section')];
const $navLinks = document.querySelectorAll('nav > a');
const navLinkOffset = 200; // navLink offset
//wheel up/down 시 이전/다음 섹션
window.addEventListener('wheel', function (e) {
const currentSectionNumber = checkCurrentSectionNumber();
e.deltaY > 0
? window.scrollTo(
0,
$sections[currentSectionNumber]?.offsetTop ||
$sections[currentSectionNumber - 1].offsetTop
) // 휠 다운
: window.scrollTo(0, $sections[currentSectionNumber - 2]?.offsetTop); // 휠 업
});
//scroll 시 top_menu 색 변경 로직
window.addEventListener('scroll', function (e) {
const $topMenu = document.querySelector('.top_menu');
window.scrollY > 100
? $topMenu.classList.add('on')
: $topMenu.classList.remove('on');
// sectionsTopList[index] 넘어가면 해당 index section으로 이동 (index+1)
for (var i = $sections.length - 1; i >= 0; i--) {
if (window.scrollY > $sections[i].offsetTop - navLinkOffset) {
$navLinks[i].classList.add('on');
$navLinks[i + 1]?.classList.remove('on');
$navLinks[i - 1]?.classList.remove('on');
break;
}
}
});
// 개선 - 맨 위가 아닌 100px 아래에서 판단
function checkCurrentSectionNumber() {
let checkOffsetY = 100;
for (var i = 0; i < $sections.length - 1; i++) {
const $section = $sections[i];
if (
$section.offsetTop <= window.scrollY + checkOffsetY &&
window.scrollY + checkOffsetY < $sections[i + 1].offsetTop
)
return i + 1;
}
return $sections.length; // 마지막 섹션
}
</script>
</body>
</html>
<script>
const $sections = [...document.querySelectorAll('.sec_con > section')];
const $navLinks = document.querySelectorAll('nav > a')[0];
let timerId = -1;
let isScrolling = false;
const scrollToSection = ($section, deltaY) => {
if (isScrolling) return;
isScrolling = true;
const $prevSection = $section.previousElementSibling;
const $nextSection = $section.nextElementSibling;
deltaY > 0
? window.scrollTo(0, $nextSection?.offsetTop ?? $section.offsetTop)
: window.scrollTo(0, $prevSection?.offsetTop ?? $section.offsetTop);
timerId = setTimeout(() => {
isScrolling = false;
clearTimeout(timerId);
}, 800);
};
const onWheel = function (e) {
e.preventDefault();
const { target, deltaY } = e;
if (!target.closest('.sec_con')) return; //wheel 대상이 sec_con의 자식요소인지 확인합니다.
const $section = target.closest('.sec_con > section'); // wheel 대상이 section의 자식 요소일 수도 있으므로 해당하는 section으로 $section을 할당
//target 요소는 section임
scrollToSection($section, deltaY);
};
document.addEventListener('wheel', onWheel, { passive: false });
</script>