“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”
- Frederick Philips Brooks
Mythical Man-Month 저자
자바스크립트 패럴랙스 이펙트 01_메뉴효과
💜 parallax Effect01
HTML
<!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 font10">
<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">불가능은 무엇인가? 단지 미래의 가능성을 아직 발견하지 못한 것일 뿐이다.</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>ps</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:hunmi961119@gmail.com">hunmi961119@gmail.com</a>
</footer>
<!-- //footer -->
reset.css와 parallax.css는 link stylesheet로 연결해줬습니다.
구역을 나눠 이미지 메뉴와 이미지, 좌표값 부분을 작업해줬습니다.
script
<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;
</script>
window.addEventListner("ccroll", () => {}); 윈도우 객체의 스크롤 이벤트를 감지하는 이벤트 리스너를 사용해줬습니다.
let scrollTop = window.pageY0ffset || window.scrollY || documentElement.scrollTop; 스크롤이 발생한 위치를 가져오기 위해 pageYoffset, scrollY, documentElement.scrollTop 세 가지 속성을 사용해 현재 스크롤 위치를 계산하고 scrollTop 변수에 할당합니다.
document.querySelectorAll(".parallax__item").forEach(item, index) => {}); 클래스 이름이 parallax__item 인 모든 요소들을 선택해 forEach 루프를 사용해 각 요소에 대해 처리를 수행합니다.
이 부분은 각 섹션이 스크롤 위치를 확인하고 활성화 상태를 변경하는 로직이 구현되어 있습니다.
if (scrollTop >= item.offsetTop -2) {} 스크롤 위치가 각 섹션의 위치보다 크거나 같으면, 해당 섹션의 인덱스를 기반으로 메뉴의 활성화 상태를 변경
-2를 빼는 이유는 약간의 여유를 주기 위함입니다.
document.querySelector(".parallax__nav li:nth-child(" + (index + 1)+ ")").classList.add("active"); 현재 활성화된 섹션의 인덱스를 기반으로 해당 메뉴 아이템의 클래스에 active 를 추가해 활성화 표시를 합니다.
document.querySelector(li.getAttribute("href")).scrollIntoView({behavior: "smooth"}); 클릭된 메뉴 아이템의 href 속성을 기반으로 해당 섹션의 요소를 선택해 scrollIntoView()메서드를 사용해 부드러운 스크롤로 해당 섹션으로 이동합니다.
반복문은 for문과 for Each문 for in문 for of문으로 바꿔주겠습니다.
for문
for(let i=1; i<=9; i++){
document.querySelector(`.info .offset${i}`).innerText = document.getElementById(`section${i}`).offsetTop;
}
반복문을 사용해
offsetTop값을 가져와 info .offset1부터 info .offset9 라는 클래스들의 텍스트 내용으로 설정합니다.
offsetTop 값을 .info 클랙스 하위의 offset1부터 offset9 라는 클래스들에 각각 출력합니다.
forEach문
document.querySelectorAll(".info span").forEach((e, i) => {
e.innerHTML = document.getElementById(`section${i + 1}`).offsetTop;
});
document.querySelectorAll 메서드를 사용해 .info 클래스 내부에 있는 span 요소들을 선택하고
forEach메서드를 사용해 각각의 span요소에 대해 콜백 함수를 실행하는 코드입니다.
for in 문
const infoSpans = document.querySelectorAll(".info span");
for (let i in infoSpans) {
const e = infoSpans[i];
e.innerHTML = document.getElementById(`section${parseInt(i) + 1}`).offsetTop;
}
for in 루프를 사용해 infoSpans 에 저장된 span요소들을 순환
let i in infoSpans 은 infoSpans의 인덱스를 i라는 변수에 할당
const e = infoSpans[i]는 현재 순회 중인 span 요소를 e 라는 상수에 저장
document.getElementById(`section${parseInt(i)+1}`).offsetTop은 section 이라는 ID를 가진 요소들 중에 i에 1을 더한 값을 ID로 가지는 요소의 offsetTop 값을 가져옵니다.
for of문
const infoSpans = document.querySelectorAll(".info span");
for (const e of infoSpans) {
const index = Array.from(infoSpans).indexOf(e);
e.innerHTML = document.getElementById(`section${index + 1}`).offsetTop;
}
for of 문을 사용해 infoSpans에 저장된 span 요소들을 순회
const e of infoSpan 는 infoSpans의 각 span 요소를 e 라는 상수에 할당합니다.
Array.form(infoSpans)는 infoSpans 를 배열로 변환합니다.
-indexOf 메소드를 사용하기 위해
const index = Array.from(infoSpans).indexOf(e)는 현재 순회중인 span 요소의 인덱스를 구합니다.
document.getElementById(`section${index + 1}`).offsetTop 은 section 이라는 ID를 가지 요소들 중에 index에 1을 더한 값을 ID로 가지는 요소의 offsetTop 값을 가져옵니다.
e.innerHTML = document.getElementById(`section${index + 1}`).offsetTop 은 현재 순회중인 span 요소의 내용을 해당 section 요소의 offsetTop 값으로 설정, .info 클래스를 가진 요소의 자식span 요소들의 내용이 각각의 section 요소의 offsetTop 값으로 표시