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>패럴랙스 이펙트06</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/parallax.css">
<style>
.split span {
display: inline-block;
min-width: 1vw;
opacity: 0;
transform: translateY(100px);
transition: all 0.6s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.split span.show {
opacity: 1;
transform: translateY(0);
}
/* .split.show span:nth-child(1) {transition-delay: 100ms;}
.split.show span:nth-child(2) {transition-delay: 150ms;}
.split.show span:nth-child(3) {transition-delay: 200ms;}
.split.show span:nth-child(4) {transition-delay: 250ms;}
.split.show span:nth-child(5) {transition-delay: 300ms;}
.split.show span:nth-child(6) {transition-delay: 350ms;}
.split.show span:nth-child(7) {transition-delay: 400ms;}
.split.show span:nth-child(8) {transition-delay: 450ms;}
.split.show span:nth-child(9) {transition-delay: 500ms;}
.split.show span:nth-child(10) {transition-delay: 550ms;}
.split.show span:nth-child(11) {transition-delay: 600ms;}
.split.show span:nth-child(12) {transition-delay: 650ms;}
.split.show span:nth-child(13) {transition-delay: 700ms;}
.split.show span:nth-child(14) {transition-delay: 750ms;}
.split.show span:nth-child(15) {transition-delay: 800ms;}
.split.show span:nth-child(16) {transition-delay: 850ms;}
.split.show span:nth-child(17) {transition-delay: 900ms;}
.split.show span:nth-child(18) {transition-delay: 950ms;}
.split.show span:nth-child(19) {transition-delay: 1000ms;}
.split.show span:nth-child(20) {transition-delay: 1050ms;}
.split.show span:nth-child(21) {transition-delay: 1100ms;}
.split.show span:nth-child(22) {transition-delay: 1150ms;}
.split.show span:nth-child(23) {transition-delay: 1200ms;}
.split.show span:nth-child(24) {transition-delay: 1250ms;}
.split.show span:nth-child(25) {transition-delay: 1300ms;}
.split.show span:nth-child(26) {transition-delay: 1350ms;}
.split.show span:nth-child(27) {transition-delay: 1400ms;}
.split.show span:nth-child(28) {transition-delay: 1450ms;}
.split.show span:nth-child(29) {transition-delay: 1500ms;}
.split.show span:nth-child(30) {transition-delay: 1550ms;}
.split.show span:nth-child(31) {transition-delay: 1600ms;}
.split.show span:nth-child(32) {transition-delay: 1650ms;}
.split.show span:nth-child(33) {transition-delay: 1700ms;}
.split.show span:nth-child(34) {transition-delay: 1750ms;}
.split.show span:nth-child(35) {transition-delay: 1800ms;} */
/* 기본효과 */
.style1.split span {
opacity: 0;
display: inline-block;
min-width: 1vw;
transition: all 0.3s ease-in-out;
}
.style1.split span.show {
opacity: 1;
}
/* 효과2 밑에서 올라오기 */
.style2.split span {
opacity: 0;
display: inline-block;
min-width: 1vw;
transform: translateY(100px);
transition: all 0.3s ease-in-out;
}
.style2.split span.show {
opacity: 1;
transform: translateY(0);
}
/* 효과3 회전하면서 나오기 */
.style3.split span {
opacity: 0;
display: inline-block;
min-width: 1vw;
transform: translateY(100px) translateX(-100px) rotate(360deg);
transition: all 0.3s cubic-bezier(0, 0.28, 0, 1.2);
}
.style3.split span.show {
opacity: 1;
transform: translateY(0) translateX(0) rotate(0);
}
/* 효과4 */
.style4.split span {
opacity: 0;
display: inline-block;
min-width: 1vw;
}
.style4.split span.show {
opacity: 1;
animation: wobble 0.5s 1;
}
/* 효과5 */
.style5.split span {
opacity: 0;
display: inline-block;
min-width: 1vw;
}
.style5.split span.show {
opacity: 1;
animation: pulse 0.5s 1;
}
/* 효과6 */
.style6.split span {
opacity: 0;
display: inline-block;
min-width: 1vw;
}
.style6.split span.show {
opacity: 1;
animation: flash 0.5s 1;
}
/* gsap */
/* .split {
transform-style: preserve-3d;
}
.split span {
display: inline-block;
min-width: 1vw;
opacity: 0;
transform: translate3d(-100px, 0px, -30px) rotate(300deg);
} */
@keyframes wobble {
0% {transform: translate3d(0, 0, 0); opacity: 0;}
15% {transform: translate3d(-25%, 25%, 0) rotate3d(0, 0, 1, -5deg);}
30% {transform: translate3d(20%, 20%, 0) rotate3d(0, 0, 1, 3deg);}
45% {transform: translate3d(-15%, -15%, 0) rotate3d(0, 0, 1, -3deg);}
60% {transform: translate3d(10%, 10%, 0) rotate3d(0, 0, 1, 2deg);}
75% {transform: translate3d(-5%, -5%, 0) rotate3d(0, 0, 1, -1deg);}
100% {transform: translate3d(0, 0, 0); opacity: 1;}
}
@keyframes flash {
0%,
50%,
to {opacity: 1}
25%,
75% {opacity: 0}
}
@keyframes pulse {
0% {
-webkit-transform: scaleX(1);
transform: scaleX(1)
}
50% {
-webkit-transform: scale3d(1.05, 1.05, 1.05);
transform: scale3d(1.05, 1.05, 1.05)
}
to {
-webkit-transform: scaleX(1);
transform: scaleX(1)
}
}
</style>
</head>
<body class="img01 bg01 font01">
<header id="header">
<h1>Javascript parallax Effect06</h1>
<p>패럴랙스 이펙트: 텍스트 효과</p>
<ul>
<li><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 class="active"><a href="parallaxEffect06.html">6</a></li>
<li><a href="parallaxEffect07.html">7</a></li>
</ul>
</header>
<!--header -->
<!-- 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 split style1">결과도 중요하지만, 과정을 더 즁요하게 생각한다.</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 split style2">세상 모든 일은 여러분이 무엇을 생각하느냐에 따라 일어납니다.</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 split style3">웃음은 두 사람간의 가장 가까운 거리다</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 split style4">지속적인 긍정적 사고는 능력을 배가시킨다.</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 split style5">정의는 외부에서 오는 것이 아니라 내적 평온으로부터 온다.</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 split style6">아무것도 변하지 않을지라도 내가 변하면 모든 것이 변한다</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 split">노력을 이기는 재능은 없고 노력을 외면하는 결과도 없다</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 split">사소한 것들을 소중히 해야한다. 그것이 삶을 이루는 버팀목이니까</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 split">때론 기회를 놓치는 것이 기회일 수 있다.</p>
</section>
<!--//section9-->
</div>
</main>
<!-- main -->
<footer id="footer">
<a href="mailto:lee3ll@naver.com">lee3ll@naver.com</a>
</footer>
<!-- footer -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script>
<script>
//텍스트 분리하기
// let text = document.querySelector("#section1 .parallax__item__desc");
// let splitText = text.innerText;
// let splitWrap = splitText.split('').join('</span><span>');
// text.innerHTML = splitWrap = "<span>" + splitWrap + "</span>";
//모든 텍스트 분리하기
document.querySelectorAll(".split").forEach(text => {
let splitText = text.innerText;
let splitWrap = splitText.split('').join("</span><span aria-hidden='true'>");
splitWrap = "<span aria-hidden='true'>" + splitWrap + "</span>";
text.innerHTML = splitWrap;
text.setAttribute("aria-label", splitText);
});
//CSS 스크롤 이펙트
function scroll(){
let scrollTop = window.pageYOffset || window.scrollY;
//CSS클래스 추가
document.querySelectorAll(".parallax__item").forEach(item => {
if(scrollTop > item.offsetTop){
item.querySelector(".split").classList.add("show");
}
});
//span에 show 추가
document.querySelectorAll(".parallax__item").forEach(item => {
if(scrollTop >= item.offsetTop){
item.querySelectorAll(".split span").forEach((span, index) => {
setTimeout(()=>{
span.classList.add("show");
}, 60*index)
});
}
});
//gsap
// const items = document.querySelectorAll(".parallax__item");
// items.forEach((item, itemIndex) => {
// const spans = item.querySelectorAll(".split span");
// if (scrollTop >= item.offsetTop) {
// gsap.to(spans, {
// duration: 0.1,
// opacity: 1,
// x: 0,
// y: 0,
// z: 0,
// scale:1,
// rotation: 0,
// stagger: 0.05
// });
// }
// });
requestAnimationFrame(scroll);
}
scroll();
</script>
</body>
</html>
보충설명
✨document.querySelectorAll(".split")를 사용하여 클래스가 "split"인 모든 요소를 선택합니다. 그런 다음 forEach를 사용하여 각 요소에 대해 다음 작업을 수행합니다:
✨innerText 속성을 사용하여 요소의 텍스트를 가져옵니다.
✨split 메서드를 사용하여 텍스트를 문자 단위로 분리한 다음 join 메서드를 사용하여 각 문자를 </span><span aria-hidden='true'>으로 구분한 문자열로 변환합니다.
✨생성된 문자열 앞뒤에 <span aria-hidden='true'> 태그를 추가하여 각 문자를 <span> 요소로 묶습니다.
✨innerHTML 속성을 사용하여 변경된 HTML을 해당 요소에 적용합니다.
✨setAttribute 메서드를 사용하여 aria-label 속성을 원래의 텍스트로 설정합니다.
✨scroll 함수를 정의합니다. scroll 이 함수는 스크롤 이벤트가 발생할 때 호출됩니다.
✨window.pageYOffset 또는 window.scrollY를 사용하여 현재 스크롤 위치를 가져옵니다.
✨document.querySelectorAll(".parallax__item")을 사용하여 클래스가 "parallax__item"인 모든 요소를 선택합니다. 각 요소에 대해 다음 작업을 수행합니다:
✨scrollTop 값과 요소의 offsetTop 값을 비교하여 현재 스크롤 위치가 요소의 위치보다 큰지 확인합니다.
✨조건을 만족하는 경우, 해당 요소의 자식 요소 중 클래스가 "split"인 요소를 찾아 classList.add("show")를 사용하여 "show" 클래스를 추가합니다.
✨다시 한 번 document.querySelectorAll(".parallax__item")을 사용하여 클래스가 "parallax__item"인 모든 요소를 선택합니다. 각 요소에 대해 다음 작업을 수행합니다:
✨scrollTop 값이 요소의 offsetTop 값보다 크거나 같은 경우, 해당 요소의 자식 요소 중 <span> 요소를 모두 선택합니다.
✨선택된 각 <span> 요소에 대해 setTimeout 함수를 사용하여 인덱스에 따라 지연을 주고 classList.add("show")를 사용하여 "show" 클래스를 추가합니다. 이로써 텍스트가 하나씩 나타나는 효과를 구현할 수 있습니다.
GSAP
✨코드에 GSAP (GreenSock Animation Platform) 라이브러리를 추가하여 스크롤 이펙트에 애니메이션을 적용하는 부분입니다.
✨코드의 첫 부분에서 'https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js' 경로에서 GSAP 라이브러리를 가져옵니다. 이를 통해 GSAP 함수와 기능을 사용할 수 있습니다.
✨ items라는 변수를 선언하고 document.querySelectorAll(".parallax__item")를 사용하여 클래스가 "parallax__item"인 모든 요소를 선택합니다.
✨items.forEach((item, itemIndex) => { ... })를 사용하여 items 배열의 각 요소에 대해 반복합니다. 반복되는 각 요소에 대해 다음 작업을 수행합니다:
✨item 변수는 현재 반복 중인 요소를 나타냅니다.
✨spans 변수는 현재 요소에서 클래스가 "split"인 <span> 요소들을 선택합니다.
✨scrollTop 값이 현재 요소의 offsetTop 값보다 크거나 같은 경우에만 다음 작업을 수행합니다. 이를 통해 해당 요소가 스크롤 뷰포트에 들어왔을 때 애니메이션이 실행됩니다.
✨gsap.to() 함수를 사용하여 GSAP 애니메이션을 적용합니다. 선택된 spans 배열의 각 요소에 대해 다음 애니메이션 속성을 설정합니다:
✨duration: 애니메이션의 지속 시간을 0.1초로 설정합니다.
✨opacity: 투명도를 1로 설정하여 요소를 표시합니다.
✨x, y, z: 요소의 위치를 변경하지 않고 0으로 유지합니다.
✨scale: 요소의 크기를 1로 설정하여 변경하지 않습니다.
✨rotation: 회전값을 0으로 설정하여 회전하지 않습니다.
✨stagger: 각 요소의 애니메이션 지연 시간을 0.05초로 설정하여 요소들이 차례대로 애니메이션을 수행합니다.
✨ requestAnimationFrame(scroll);을 사용하여 스크롤 이벤트 발생 시 scroll 함수를 호출하고 애니메이션을 실행합니다. scroll() 함수는 앞서 설명한 스크롤 이펙트를 구현하는 함수입니다.
✨이를 통해 GSAP를 사용하여 스크롤 이펙트에 애니메이션을 추가할 수 있습니다. GSAP는 강력한 애니메이션 라이브러리로, 편리한 애니메이션 기능과 성능 최적화를 제공합니다.