Fast Blinking Hello Kitty

JAVASCRIPT

parallax효과06

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

Whatever you can do, or dream you can, begin it. Boldness has genius, power and magic in it.

Johann Wolfgang von Goethe

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