# 25.가로스크롤

In 
ui

# 목차

  • 1. 가로방향 스크롤
    • 1.1. 예제
      • 1.1.1. 가로방향
      • 1.1.2. 가로+세로 스티키

# 1. 가로방향 스크롤

횡스크롤을 제작해보자

# 1.1. 예제

# 1.1.1. 가로방향

실행화면

<main>
	<section>
		<h1>Boop</h1>
	</section>
	<section>
		<h1>Boooom</h1>
	</section>
	<section>
		<h1>Boooom</h1>
	</section>
	<section>
		<h1>The End</h1>
	</section>
</main>
html,
body {
	margin: 0;
	font-family: sans-serif;
}

main {
	overflow-x: hidden;
	display: flex;
}

section {
	min-width: 100vw;
	min-height: 100vh;
	display: flex;
	justify-content: center;
	align-items: center;
	font-size: 4em;
}

section:nth-child(even) {
	background-color: teal;
	color: white;
}
const scrollContainer = document.querySelector('main');
scrollContainer.addEventListener('wheel', (e) => {
	e.preventDefault();
	//scrollLeft 요소의 수평 스크롤 바 위치를 반환 , e.deltaY 스크롤방향을 반환 (우측:100,좌측:-100)
	//scrollContainer의 수평 스크롤 바 위치에 스크롤 방향을 합하여 가로스크롤양이 가산되며 이동한다.
	let amt = (scrollContainer.scrollLeft += e.deltaY);
});

부드러운 이동 실행화면

const scrollContainer = document.querySelector('main');

let target = 0;
let ease = 0.1; // 부드러운 이동을 위한 변화 정도

// 부드럽게 이동하는 함수
function smoothScroll() {
	scrollContainer.scrollLeft += (target - scrollContainer.scrollLeft) * ease;
	requestAnimationFrame(smoothScroll); // 부드럽게 이동하도록 애니메이션 추가
}

scrollContainer.addEventListener('wheel', (e) => {
	e.preventDefault();
	target += e.deltaY; // 스크롤 목표 위치 변경
});

smoothScroll(); // 함수 실행

# 1.1.2. 가로+세로 스티키

실행화면

<div class="vertical">HELLO</div>
<div class="sticky">
	<main>
		<section>
			<h1>Beep</h1>
		</section>
		<section>
			<h1>Boop</h1>
		</section>
		<section>
			<h1>Boooom</h1>
		</section>
		<section>
			<h1>The End</h1>
		</section>
	</main>
</div>
<div class="vertical">DEVELOPER</div>
<div class="sticky">
	<main>
		<section>
			<h1>Beep</h1>
		</section>
		<section>
			<h1>Boop</h1>
		</section>
		<section>
			<h1>Boooom</h1>
		</section>
		<section>
			<h1>The End</h1>
		</section>
	</main>
</div>
html,
body {
	margin: 0;
	font-family: sans-serif;
}

.vertical {
	height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
}

main {
	overflow-x: hidden;
	display: flex;
	position: sticky;
	top: 0;
}

h1 {
	margin: 0;
	padding: 0;
}

section {
	min-width: 50vw;
	min-height: 100vh;
	display: flex;
	justify-content: center;
	align-items: center;
	font-size: 4ch;
}

section:nth-child(even) {
	background-color: teal;
	color: white;
}
(function () {
	let g_canScroll;
	init();
	//초기화
	function init() {
		setSticky();
		bindEvents();
	}

	function bindEvents() {
		window.addEventListener('wheel', wheelHandler);
	}

	function setSticky() {
		document.querySelectorAll('.sticky').forEach(function (container) {
			// scrollWidth=전체 스크롤바를 사용하게 되어 숨겨진 영역까지 포함한 크기를 리턴
			const stikyContainerHeight = container.querySelector('main').scrollWidth;
			//.sticky의 높이를 각각 스크롤 너비와 같게 함
			container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
		});
	}
	//요소가 화면에 들어왔는지를 확인하는 함수
	function isInView(el) {
		const rect = el.getBoundingClientRect();
		//요소가 화면에 있을경운
		console.log('document.documentElement', document.documentElement);
		return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
	}

	function wheelHandler(e) {
		// https://ko.javascript.info/iterable

		const elInView = Array.from(document.querySelectorAll('.sticky')).filter(function (el) {
			return isInView(el);
		})[0];
		if (!elInView) {
			return;
		}
		console.log('elInView', elInView);
		let isPlaceHolderBelowTop = elInView.offsetTop < document.documentElement.scrollTop; //.sticky-container의 상단좌표를 스크롤보다 작은지 비교
		let isPlaceHolderBelowBottom = elInView.offsetTop + elInView.offsetHeight > document.documentElement.scrollTop; //.sticky-container 탑과 높이를 합하고(길이) 스크롤양보다 큰지비교
		g_canScroll = isPlaceHolderBelowTop && isPlaceHolderBelowBottom; //true 는 보이는 상태
		console.log(elInView, elInView.offsetTop, isPlaceHolderBelowBottom);
		elInView.querySelector('main').scrollLeft += e.deltaY;
	}
})();