바닐라 자바스크립트로 일정 섹션에 도달하면, 세로 스크롤을 잠그고 가로 스크롤로 이동하는 페이지를 만들고 싶어 시작했는데, 생각보다 삽질이 길어져 쓰는 기록
휠의 동작을 감지하고, 스크롤의 현재 위치를 파악해서 스크롤을 자연스럽게 전환하하게 만들고 싶어서 아래와 같이 작성했는데, 조건 간에 서로 충돌되는 부분이 있어 내가 원하는 대로 작동하지 않았다.
초안 코드
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Horizontal Scroll Effect</title>
<style>
body, html {
margin: 0;
padding: 0;
overflow-x: hidden;
}
.section {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.horizontal-scroll-wrapper {
height: 100vh;
overflow: hidden;
position: relative;
}
.horizontal-scroll {
display: flex;
position: absolute;
top: 0;
left: 0;
min-width: 300%; /* Adjust based on content */
height: 100vh;
transition: transform 0.5s ease;
}
.horizontal-section {
width: 100vw;
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div class="section">Vertical Section 1</div>
<div class="horizontal-scroll-wrapper" id="horizontalScroll">
<div class="horizontal-scroll">
<div class="horizontal-section">Horizontal 1</div>
<div class="horizontal-section">Horizontal 2</div>
<div class="horizontal-section">Horizontal 3</div>
</div>
</div>
<div class="section">Vertical Section 2</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const horizontalScrollWrapper = document.getElementById('horizontalScroll');
let isHorizontalScrolling = false;
let horizontalScrollEnabled = false;
const wrapperOffsetTop = horizontalScrollWrapper.offsetTop;
const maxHorizontalScroll = horizontalScrollWrapper.scrollWidth - horizontalScrollWrapper.clientWidth;
window.addEventListener('wheel', (e) => {
const scrollY = window.scrollY;
// 세로 스크롤을 가로 스크롤로 전환
if (scrollY >= wrapperOffsetTop && !isHorizontalScrolling) { //가로스크롤 상태가 false이고, 스크롤의 위치가 가로섹션의 시작점과 같거나 아래에 있을 때
if (e.deltaY > 0) { // 휠 내림
e.preventDefault();
isHorizontalScrolling = true;
horizontalScrollEnabled = true;
horizontalScrollWrapper.scrollLeft += 10; // 예시 이동 값
} else if (e.deltaY < 0 && horizontalScrollWrapper.scrollLeft === 0) { // 휠 올림, 가로 스크롤 최왼쪽
e.preventDefault();
window.scrollTo(0, scrollY - 10); // 위로 스크롤
}
// else if (e.deltaY < 0 && scrollY > wrapperOffsetTop) { //휠 올림, 가로섹션보다 스크롤이 아래일 때, 가로스크롤 최좌측 아닐때
// console.log('휠 올리고 있고, 스크롤 위치는 가로섹션보다 아래임. ');
// }
}
if (isHorizontalScrolling && horizontalScrollEnabled) {
if (e.deltaY > 0 && horizontalScrollWrapper.scrollLeft < maxHorizontalScroll) { // 가로 스크롤 우측으로 이동
e.preventDefault();
horizontalScrollWrapper.scrollLeft += 10;
} else if (e.deltaY > 0 && horizontalScrollWrapper.scrollLeft >= maxHorizontalScroll) { // 가로 스크롤 끝, 세로 스크롤 재개
horizontalScrollEnabled = false;
} else if (e.deltaY < 0 && horizontalScrollWrapper.scrollLeft > 0) { // 가로 스크롤 좌측으로 이동
e.preventDefault();
horizontalScrollWrapper.scrollLeft -= 10;
} else if (e.deltaY < 0 && horizontalScrollWrapper.scrollLeft <= 0) { // 가로 스크롤 최왼쪽, 세로 스크롤 재개
isHorizontalScrolling = false;
window.scrollTo(0, scrollY - 10); // 위로 스크롤
}
}
// if (!horizontalScrollEnabled && e.deltaX < 0 && scrollY === wrapperOffsetTop && horizontalScrollWrapper.scrollLeft >= maxHorizontalScroll) {
// console.log('가로스크롤이 해제되었고, 휠을 올라가는 동작중이고, 스크롤의 위치가 가로섹션의 시작점이고, 가로스크롤은 최우측에 있음');
// }
// 스크롤이 가로 섹션보다 아래에 있고, 위로 올라가는 경우 가로 스크롤 활성화 로직
if (scrollY > wrapperOffsetTop && e.deltaY < 0 && !horizontalScrollEnabled) {
if(scrollY === wrapperOffsetTop) { //스크롤이 가로섹션에 닿을 때
e.preventDefault(); // 기본 스크롤 동작 방지
horizontalScrollEnabled = true; //가로스크롤 활성화하기
isHorizontalScrolling = true;
}
}
},{ passive: false });
});
</script>
</body>
</html>
몇 차례 수정한 현재 코드
이 수정한 코드는 원하는 동작을 하긴 하지만, 여전히 동작의 버벅거림이 발생한다..
<script>
document.addEventListener('DOMContentLoaded', () => {
const horizontalScrollWrapper = document.getElementById('horizontalScroll');
let isHorizontalScrolling = false;
let horizontalScrollEnabled = false;
const wrapperOffsetTop = horizontalScrollWrapper.offsetTop;
const maxHorizontalScroll = horizontalScrollWrapper.scrollWidth - horizontalScrollWrapper.clientWidth;
window.addEventListener('wheel', (e) => {
const scrollY = window.scrollY;
const shouldEnableHorizontalScroll = scrollY >= wrapperOffsetTop && scrollY <= (wrapperOffsetTop + horizontalScrollWrapper.offsetHeight);
// 스크롤이 가로 섹션의 시작점보다 아래에 있을 때
if (shouldEnableHorizontalScroll && !isHorizontalScrolling) {
e.preventDefault(); // 기본 스크롤 동작 방지
isHorizontalScrolling = true;
horizontalScrollEnabled = true;
// 휠 동작 방향에 따라 가로 스크롤 조정
horizontalScrollWrapper.scrollLeft += e.deltaY > 0 ? 10 : -10;
}
// 가로 스크롤 활성화 및 동작 로직
if (isHorizontalScrolling && horizontalScrollEnabled) {
if (horizontalScrollWrapper.scrollLeft < maxHorizontalScroll && e.deltaY > 0) { // 우측으로 스크롤
e.preventDefault();
horizontalScrollWrapper.scrollLeft += 10;
} else if (horizontalScrollWrapper.scrollLeft > 0 && e.deltaY < 0) { // 좌측으로 스크롤
e.preventDefault();
horizontalScrollWrapper.scrollLeft -= 10;
} else {
// 가로 스크롤이 끝에 도달하면 세로 스크롤 활성화
isHorizontalScrolling = false;
horizontalScrollEnabled = false;
}
}
// 스크롤이 가로 섹션보다 아래에 있고, 위로 올라가는 경우 가로 스크롤 활성화 로직
if (scrollY >= wrapperOffsetTop && e.deltaY < 0 && !horizontalScrollEnabled) {
if(scrollY === wrapperOffsetTop) { //스크롤이 가로섹션에 닿을 때
e.preventDefault(); // 기본 스크롤 동작 방지
horizontalScrollEnabled = true; //가로스크롤 활성화하기
isHorizontalScrolling = true;
}
}
},{ passive: false });
});
</script>
계속 수정중...