Fast Blinking Hello Kitty

JAVASCRIPT

parallax효과06

코른이되고싶은코린이 2023. 5. 17. 23:07

728x90

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는 강력한 애니메이션 라이브러리로, 편리한 애니메이션 기능과 성능 최적화를 제공합니다.