JAVASCRIPT

패럴랙스 (parallax) 이펙트 ( 4 ) (gsap, scrollTop , offsetTop, innerHeight)

김도현2 2023. 5. 17. 19:18
반응형

패럴랙스 (parallax) 이펙트 ( 4 ) (gsap, scrollTop , offsetTop, innerHeight)

 

 

 

 

 

 

 

 

 

 

VSCode

<!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>
    <style>
        /* .split span:nth-child(odd) {
            display: inline-block;
            min-width: 1vw;
            opacity: 0;
            transform: translateY(100px);
            transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
        }
        .split span:nth-child(even) {
            display: inline-block;
            min-width: 1vw;
            opacity: 0;
            transform: translateY(-100px);
            transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
        }
        .split span.show {
            opacity: 1;
            transform: translateY(0);
        } */

        /* 기본효과 */
        /* .style1.split span {
            opacity: 0;
            display: inline-block;
            min-width: 1vw;
            transition: all 0.3s ease-in-out;
            
        }
        .style1.split span.show {
            opacity: 1;
            
        } */
        /* 밑에서 올라오기 */
        /* .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);
        } */
        /* 한바퀴 돌기 */
        /* .style3.split span {
            opacity: 0;
            display: inline-block;
            min-width: 1vw;
            transform: translateY(50px) translateX(-50px) rotate(500deg);
            transition: all 0.3s ease-in-out;
            
        }
        .style3.split span.show {
            opacity: 1;
            transform: translateY(0) translateX(0);
        } */
        /* 애니메이션 */
        /* .style4.split span {
            opacity: 0;
            display: inline-block;
            min-width: 1vw;
        }
        .style4.split span.show {
            opacity: 1;
            animation: wobble 0.3s 1;
        }
        @keyframes wobble {
            0%   {transform: translate3d(0, 0, 0); opacity: 0;}
            15%  {transform: translate3d(-25%, 25%, 0) rotate3d(0, 0, 3, -5deg);}
            30%  {transform: translate3d(20%, -25%, 0) rotate3d(0, 0, 5, 3deg);}
            45%  {transform: translate3d(-15%, 20%, 0) rotate3d(0, 0, 2, -3deg);}
            60%  {transform: translate3d(10%, -20, 0) rotate3d(0, 0, 7, 2deg);}
            75%  {transform: translate3d(-5%, 10%, 0) rotate3d(0, 0, 9, -1deg);}
            100% {transform: translate3d(0, 0, 0); opacity: 1;}
        } */

        /* 애니메이션 */
        /* .style5.split span {
            opacity: 0;
            display: inline-block;
            min-width: 1vw;
        }
        .style5.split span.show {
            opacity: 1;
            animation: rotateOutDownLeft 0.6s 1;
        }
        @keyframes rotateOutDownLeft {
            0% {
                opacity: 1
            }

            to {
                -webkit-transform: rotate(45deg);
                transform: rotate(45deg);
                opacity: 0
            }
        }

        .style6.split span {
            opacity: 0;
            display: inline-block;
            min-width: 1vw;
        }
        .style6.split span.show {
            opacity: 1;
            animation: bounceInUp 0.7s 1 cubic-bezier(0.19, 1, 0.22, 1);
        }
        @keyframes bounceInUp {

            0%,
            60%,
            75%,
            90%,
            to {
                -webkit-animation-timing-function: cubic-bezier(.215, .61, .355, 1);
                animation-timing-function: cubic-bezier(.215, .61, .355, 1)
            }

            0% {
                opacity: 0;
                -webkit-transform: translate3d(0, 3000px, 0) scaleY(5);
                transform: translate3d(0, 3000px, 0) scaleY(5)
            }

            60% {
                opacity: 1;
                -webkit-transform: translate3d(0, -20px, 0) scaleY(.9);
                transform: translate3d(0, -20px, 0) scaleY(.9)
            }

            75% {
                -webkit-transform: translate3d(0, 10px, 0) scaleY(.95);
                transform: translate3d(0, 10px, 0) scaleY(.95)
            }

            90% {
                -webkit-transform: translate3d(0, -5px, 0) scaleY(.985);
                transform: translate3d(0, -5px, 0) scaleY(.985)
            }

            to {
                -webkit-transform: translateZ(0);
                transform: translateZ(0)
            }
        } */

        .split span {
            opacity: 0;
            display: inline-block;
            min-width: 1vw;
            transform: translate3d(50px, 100px, 30px) rotate(200deg) scale(50);
        }
        /* .split span:nth-child(1) {transition-delay: 100ms;}
        .split span:nth-child(2) {transition-delay: 150ms;}
        .split span:nth-child(3) {transition-delay: 200ms;}
        .split span:nth-child(4) {transition-delay: 250ms;}
        .split span:nth-child(5) {transition-delay: 300ms;}
        .split span:nth-child(6) {transition-delay: 350ms;}
        .split span:nth-child(7) {transition-delay: 400ms;}
        .split span:nth-child(8) {transition-delay: 450ms;}
        .split span:nth-child(9) {transition-delay: 500ms;}
        .split span:nth-child(10) {transition-delay: 550ms;}
        .split span:nth-child(11) {transition-delay: 600ms;}
        .split span:nth-child(12) {transition-delay: 650ms;}
        .split span:nth-child(13) {transition-delay: 700ms;}
        .split span:nth-child(14) {transition-delay: 750ms;}
        .split span:nth-child(15) {transition-delay: 800ms;}
        .split span:nth-child(16) {transition-delay: 850ms;}
        .split span:nth-child(17) {transition-delay: 900ms;}
        .split span:nth-child(18) {transition-delay: 950ms;}
        .split span:nth-child(19) {transition-delay: 1000ms;}
        .split span:nth-child(20) {transition-delay: 1050ms;}
        .split span:nth-child(21) {transition-delay: 1100ms;}
        .split span:nth-child(22) {transition-delay: 1150ms;}
        .split span:nth-child(23) {transition-delay: 1200ms;}
        .split span:nth-child(24) {transition-delay: 1250ms;}
        .split span:nth-child(25) {transition-delay: 1300ms;}
        .split span:nth-child(26) {transition-delay: 1350ms;} */
    </style>

    <link rel="stylesheet" href="css/reset.css">
    <link rel="stylesheet" href="css/parallax.css">
</head>
<body class="bg01 font05">
    <header id="header">
        <h1><a href="https://ehcjswo.github.io/web2023/index.html">Javascript parallax Effect01</a></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-->

    <main id="main">
        <div id="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 style7">불가능한 일을 해보는 것은 신나는 일이다.</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 style8">당신이 포기할 때, 나는 시작한다.</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 style9">나이가 성숙을 보장하지는 않는다.</p>
            </section>
            <!-- //section9 -->
            
            
        </div>
    </main>
    <!-- //main -->


    <footer id="footer">
        <a href="mailto:ehcjswo1@gmail.com">ehcjswo1@gmail.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);
        });

        

        // 스크롤 이펙트
        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");
            //             }, 50*(index))
            //         });
            //     }
            // });

            // gsap
            const items = document.querySelectorAll(".parallax__item");

            items.forEach((item, itemIndex) => {
                if (scrollTop >= item.offsetTop) {
                    const spans = item.querySelectorAll(".split span");

                    gsap.to(spans, {
                        duration: 0.15,
                        opacity: 1,
                        stagger: 0.04,
                        rotate: 1,
                        scale:1,
                        x:0,
                        y:0,
                        z:0
                    });
                }
            });

            requestAnimationFrame(scroll);
        }
        scroll()

        



    </script>
</body>
</html>

 

패럴랙스 효과는 스크롤 이벤트를 이용하여 웹 페이지 요소들을 다양한 방식으로 움직이거나 변형시키는 기술입니다.

이 코드에서는 scroll() 함수를 통해 스크롤 이벤트를 처리하고, 각 섹션 내의 이미지와 텍스트를 움직이는 애니메이션 효과를 부여합니다.

 

 

 

 

script

<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);
        });

        

        // 스크롤 이펙트
        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");
            //             }, 50*(index))
            //         });
            //     }
            // });

            // gsap
            const items = document.querySelectorAll(".parallax__item");

            items.forEach((item, itemIndex) => {
                if (scrollTop >= item.offsetTop) {
                    const spans = item.querySelectorAll(".split span");

                    gsap.to(spans, {
                        duration: 0.15,
                        opacity: 1,
                        stagger: 0.04,
                        rotate: 1,
                        scale:1,
                        x:0,
                        y:0,
                        z:0
                    });
                }
            });

            requestAnimationFrame(scroll);
        }
        scroll()
        
    </script>

GSAP 라이브러리를 로드하기 위해 외부 스크립트 파일을 가져오고 있습니다.

 

주석 처리된 부분은 특정 요소의 텍스트를 분리하여 각 문자를 <span> 요소로 감싸는 기능입니다. 해당 요소의 클래스가 "split"으로 지정되어 있어야 합니다. 이 기능은 문서 내 모든 클래스가 "split"인 요소에 적용됩니다. 분리된 텍스트는 화면에서 보이지 않는 상태로 숨겨지며, aria-label 속성을 통해 원래 텍스트를 대체합니다.

 

스크롤 이벤트 처리 함수 scroll은 사용자의 스크롤 위치를 감지하고, 특정 요소들에 CSS 클래스를 추가하거나 GSAP를 사용하여 애니메이션 효과를 적용합니다. 주석 처리된 부분은 일반적인 CSS 클래스를 추가하여 텍스트가 화면에 표시되도록 하는 방식이고, 그 아래의 주석 처리되지 않은 부분은 GSAP를 사용하여 텍스트가 부드럽게 나타나도록 하는 방식입니다. GSAP의 to 메서드를 사용하여 요소의 자식 <span>들에 대해 애니메이션 속성을 설정하고, stagger 옵션을 사용하여 각 문자의 애니메이션을 일정한 간격으로 지연시킵니다.

 

마지막으로 requestAnimationFrame을 사용하여 scroll 함수가 매 프레임마다 호출되도록 합니다. 이를 통해 스크롤 이벤트가 발생할 때마다 애니메이션이 업데이트됩니다.

 

이 코드는 텍스트 분리 및 스크롤 애니메이션 효과를 제공하는 간단한 예시일 뿐, 전체적인 웹 페이지 구조나 이벤트 처리 등에 대한 내용은 제공되지 않았으므로 완전한 이해를 위해서는 해당 내용이 필요합니다.