패럴랙스(Parallax)는 웹 디자인에서 많이 사용되는 효과 중 하나로, 여러 레이어를 겹쳐 놓고 스크롤링에 따라 각각의 레이어가 서로 다른 속도로 움직이는 것으로 화면 전환 효과를 만드는 방식입니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>패럴랙스 이펙트01</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/parallax.css">
</head>
<body class="img01 bg01 font01">
<header id="header">
<h1>Javascript Parallax Effect01</h1>
<p>패럴랙스 이펙트 : 메뉴 효과</p>
<ul>
<li class="active"><a href="parallaxEffect01.html">1</a></li>
<li><a href="parallaxEffect02.html">2</a></li>
<li><a href="parallaxEffect03.html">3</a></li>
<li><a href="parallaxEffect04.html">4</a></li>
<li><a href="parallaxEffect05.html">5</a></li>
<li><a href="parallaxEffect06.html">6</a></li>
<li><a href="parallaxEffect07.html">7</a></li>
</ul>
</header>
<!-- //header -->
<nav class="parallax__nav">
<ul>
<li class="active"><a href="#section1">메뉴1</a></li>
<li><a href="#section2">메뉴2</a></li>
<li><a href="#section3">메뉴3</a></li>
<li><a href="#section4">메뉴4</a></li>
<li><a href="#section5">메뉴5</a></li>
<li><a href="#section6">메뉴6</a></li>
<li><a href="#section7">메뉴7</a></li>
<li><a href="#section8">메뉴8</a></li>
<li><a href="#section9">메뉴9</a></li>
</ul>
</nav>
<!-- //parallax__nav -->
<main id="main">
<div class="parallax__wrap">
<section id="section1" class="parallax__item">
<span class="parallax__item__num">01</span>
<h2 class="parallax__item__title">Section1</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">결과도 중요하지만, 과정을 더 중요하게 생각한다.</p>
</section>
<!-- //section1 -->
<section id="section2" class="parallax__item">
<span class="parallax__item__num">02</span>
<h2 class="parallax__item__title">Section2</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">산다는것 그것은 치열한 전투이다.</p>
</section>
<!-- //section2 -->
<section id="section3" class="parallax__item">
<span class="parallax__item__num">03</span>
<h2 class="parallax__item__title">Section3</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">하루에 3시간을 걸으면 7년 후에 지구를 한바퀴 돌 수 있다. </p>
</section>
<!-- //section3 -->
<section id="section4" class="parallax__item">
<span class="parallax__item__num">04</span>
<h2 class="parallax__item__title">Section4</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">언제나 현재에 집중할수 있다면 행복할것이다.</p>
</section>
<!-- //section4 -->
<section id="section5" class="parallax__item">
<span class="parallax__item__num">05</span>
<h2 class="parallax__item__title">Section5</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">진정으로 웃으려면 고통을 참아야하며 , 나아가 고통을 즐길 줄 알아야 해</p>
</section>
<!-- //section5 -->
<section id="section6" class="parallax__item">
<span class="parallax__item__num">06</span>
<h2 class="parallax__item__title">Section6</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">직업에서 행복을 찾아라. 아니면 행복이 무엇인지 절대 모를 것이다.</p>
</section>
<!-- //section6 -->
<section id="section7" class="parallax__item">
<span class="parallax__item__num">07</span>
<h2 class="parallax__item__title">Section7</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">신은 용기있는자를 결코 버리지 않는다.</p>
</section>
<!-- //section7 -->
<section id="section8" class="parallax__item">
<span class="parallax__item__num">08</span>
<h2 class="parallax__item__title">Section8</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">단순하게 살아라. 현대인은 쓸데없는 절차와 일 때문에 얼마나 복잡한 삶을 살아가는가?</p>
</section>
<!-- //section8 -->
<section id="section9" class="parallax__item">
<span class="parallax__item__num">09</span>
<h2 class="parallax__item__title">Section9</h2>
<figure class="parallax__item__imgWrap">
<div class="parallax__item__img"></div>
</figure>
<p class="parallax__item__desc">먼저 자신을 비웃어라. 다른 사람이 당신을 비웃기 전에</p>
</section>
<!-- //section9 -->
</div>
</main>
<!-- //main -->
<aside class="parallax__info">
<div class="scroll">scrollTop : <span>0</span>px</div>
<div class="info">
<ul>
<li>#section1 offset() : <span class="offset1">0</span>px</li>
<li>#section2 offset() : <span class="offset2">0</span>px</li>
<li>#section3 offset() : <span class="offset3">0</span>px</li>
<li>#section4 offset() : <span class="offset4">0</span>px</li>
<li>#section5 offset() : <span class="offset5">0</span>px</li>
<li>#section6 offset() : <span class="offset6">0</span>px</li>
<li>#section7 offset() : <span class="offset7">0</span>px</li>
<li>#section8 offset() : <span class="offset8">0</span>px</li>
<li>#section9 offset() : <span class="offset9">0</span>px</li>
</ul>
</div>
</aside>
<!-- parallax__info -->
<footer id="footer">
<a href="mailto:ebmdols@naver.com">ebmdols@naver.com</a>
</footer>
<!-- footer -->
</body>
</html>
HTML에서는 <main> 요소 안에 <section> 요소들이 포함되어 있으며, 각 섹션마다 id 값과 클래스를 부여하여 CSS에서 스타일을 지정합니다. CSS에서는 각 섹션의 배경 이미지를 지정하고, 각 요소가 스크롤 될 때 움직이는 속도와 방향을 설정합니다.
이 코드를 실행하면 스크롤 시, 배경 이미지가 다르게 움직이는 패럴랙스 효과가 나타납니다.
<script>
window.addEventListener("scroll", () => {
let scrollTop = window.pageYOffset || window.scrollY || document.documentElement.scrollTop;
document.querySelectorAll(".parallax__item").forEach((item, index) => {
if(scrollTop >= item.offsetTop -2){
document.querySelectorAll(".parallax__nav li").forEach((li) => {
li.classList.remove("active");
});
document.querySelector(".parallax__nav li:nth-child("+(index+1)+")").classList.add("active")
}
});
document.querySelectorAll(".parallax__nav li a").forEach(li => {
li.addEventListener("click", (e) => {
e.preventDefault();
document.querySelector(li.getAttribute("href")).scrollIntoView({
behavior: "smooth"
})
})
})
//info
document.querySelector(".scroll span").innerText = parseInt(scrollTop);
// document.querySelector(".info .offset1").innerText = document.getElementById("section1").offsetTop;
// document.querySelector(".info .offset2").innerText = document.getElementById("section2").offsetTop;
// document.querySelector(".info .offset3").innerText = document.getElementById("section3").offsetTop;
// document.querySelector(".info .offset4").innerText = document.getElementById("section4").offsetTop;
// document.querySelector(".info .offset5").innerText = document.getElementById("section5").offsetTop;
// document.querySelector(".info .offset6").innerText = document.getElementById("section6").offsetTop;
// document.querySelector(".info .offset7").innerText = document.getElementById("section7").offsetTop;
// document.querySelector(".info .offset8").innerText = document.getElementById("section8").offsetTop;
// document.querySelector(".info .offset9").innerText = document.getElementById("section9").offsetTop;
//for
// for(let i=1; i<10; i++){
// document.querySelector(`.info .offset${[i]}`).innerText = document.getElementById(`section${[i]}`).offsetTop;
// }
//forEach
// document.querySelectorAll(".info li span").forEach((el, index) => {
// document.querySelectorAll(".info li span")[index].innerText = document.getElementById(`section${index+1}`).offsetTop + "px";
// });
//for in
const arr = document.querySelectorAll(".info li span");
let arrIndex = 0;
for(let el in arr){
if(arr.hasOwnProperty(el)){
arrIndex++;
arr[el].innerText = document.getElementById(`section${arrIndex}`).offsetTop + "px";
}
}
//for of
// const arr = document.querySelectorAll(".info li span");
// let arrIndex = 0;
// for(let el of arr){
// arrIndex++;
// el.innerText = document.getElementById(`section${arrIndex}`).offsetTop + "px";
// }
});
</script>
let scrollTop = window.pageYOffset || window.scrollY || document.documentElement.scrollTop;
window.pageYOffset은 브라우저 창에서 문서의 맨 위에서부터 수직으로 스크롤된 픽셀 수를 나타냅니다. 이 값이 정의되어 있지 않으면 window.scrollY 값을 참조하고, 이 값도 정의되어 있지 않으면 document.documentElement.scrollTop 값을 참조합니다.
document.querySelectorAll(".parallax__nav li a").forEach(li => {
li.addEventListener("click", (e) => {
e.preventDefault();
document.querySelector(li.getAttribute("href")).scrollIntoView({
behavior: "smooth"
})
})
})
이 코드는 페이지 내에서 "parallax__nav" 클래스가 지정된 요소들 중에 "li" 요소를 찾아서, 해당 "li" 요소의 하위 요소인 "a" 태그에 클릭 이벤트를 추가하는 코드입니다.
클릭 이벤트 발생 시, 기본 동작인 링크 이동을 막기 위해 e.preventDefault() 메소드를 사용합니다. 그리고 클릭한 "a" 태그가 가리키는 섹션의 상단으로 부드럽게 스크롤하기 위해 scrollIntoView() 메소드를 사용합니다. 이 때, behavior: "smooth" 옵션을 설정하여 스크롤을 부드럽게 처리합니다.
preventDefault()는 이벤트의 기본 동작을 막는 메소드입니다. 일반적으로 이벤트가 발생하면 해당 이벤트에 맞는 브라우저의 기본 동작이 발생합니다. preventDefault()를 호출하면 이 기본 동작을 막을 수 있습니다.
window 객체의 scroll 이벤트에 대한 리스너를 추가하고, 현재 스크롤 위치를 계산합니다. 그리고, querySelectorAll 메소드를 사용하여 parallax__item 클래스를 가진 모든 요소들에 대해 반복문을 수행하면서, 현재 스크롤 위치가 해당 요소의 offsetTop 값보다 크거나 같은 경우, 해당 요소의 인덱스를 찾아 parallax__nav 클래스를 가진 메뉴 요소 중 해당 인덱스를 가진 li 태그에 active 클래스를 추가합니다.
또한, querySelectorAll 메소드를 사용하여 parallax__nav 클래스를 가진 모든 메뉴 아이템 요소에 대해 반복문을 수행하면서, 클릭 이벤트에 대한 리스너를 추가합니다. 클릭 이벤트가 발생하면, 클릭한 메뉴 아이템의 href 속성값에 해당하는 요소로 스크롤 이동을 하는 스크롤 애니메이션을 적용합니다.
document.querySelector(".scroll span").innerText = parseInt(scrollTop);
해당 코드는 현재 스크롤 위치를 나타내기 위한 것입니다. 스크롤 위치가 변경될 때마다 해당 코드가 실행되어 현재 스크롤 위치를 나타내는 스팬 요소의 텍스트 내용을 변경합니다.
스크롤 위치를 나타내는 변수 scrollTop 값을 parseInt() 함수를 사용하여 정수로 변환한 후, 스크롤 위치를 나타내는 스팬 요소의 텍스트 내용으로 할당합니다. 이를 통해 사용자가 페이지를 스크롤할 때마다 스크롤 위치에 대한 정보를 표시할 수 있습니다.
document.querySelector(".info .offset1").innerText = document.getElementById("section1").offsetTop;
document.querySelector(".info .offset2").innerText = document.getElementById("section2").offsetTop;
document.querySelector(".info .offset3").innerText = document.getElementById("section3").offsetTop;
document.querySelector(".info .offset4").innerText = document.getElementById("section4").offsetTop;
document.querySelector(".info .offset5").innerText = document.getElementById("section5").offsetTop;
document.querySelector(".info .offset6").innerText = document.getElementById("section6").offsetTop;
document.querySelector(".info .offset7").innerText = document.getElementById("section7").offsetTop;
document.querySelector(".info .offset8").innerText = document.getElementById("section8").offsetTop;
document.querySelector(".info .offset9").innerText = document.getElementById("section9").offsetTop;
해당 코드는 id가 "section1"부터 "section9"까지인 요소들의 offsetTop 값을 각각 info 클래스의 "offset1"부터 "offset9"까지인 span 요소의 innerText에 넣어주는 코드입니다.
offsetTop 값은 요소의 offsetParent를 기준으로 한 요소의 위쪽 가장자리(top)까지의 거리를 나타내며, 이 값을 통해 각 요소가 현재 스크롤 위치에서 어느 정도 떨어져 있는지를 알 수 있습니다. 따라서 이 코드는 스크롤할 때마다 현재 스크롤 위치에 따라 각 요소가 어느 정도 떨어져 있는지를 보여주는 정보를 업데이트해줍니다.