Animated Turtle

Javascript

패럴랙스 이펙트

훙구 2023. 5. 17. 23:16

...

728x90
반응형

패럴랙스 이펙트로 각각의 효과 주기

각각의 스타일 애니메이션을 만들어 메세지에 효과를 줘보겠습니다.

 

 

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>패럴렉스 이펙트06</title>

    <link rel="stylesheet" href="css/reset.css">
    <link rel="stylesheet" href="css/parallax.css">
</head>
<body class="img01 bg01 gmarketsans container">
    <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>
            <li><a href="parallaxEffect07.html">8</a></li>
            <li><a href="parallaxEffect07.html">9</a></li>
            <li><a href="parallaxEffect07.html">10</a></li>
        </ul>
    </header>
    <!-- header -->

    <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 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">사람 고쳐 쓰는거 아니다.</p>
            </section>
            <!-- section9 -->
        </div>
    </main>
    <!-- main -->

    <footer id="footer">
        <a href="mailto:gnsrbdi@naver.com">gnsrdbi@naver.com</a>
    </footer>
</body>
</html>

CSS 살펴보기

.split span {
    display: inline-block;
    min-width: 1vw;
    opacity: 0;
    transform: translateY(100px);
    transition: all 0.6s cubic-bezier(0.54, 0.01, 0, 1);
}
.split span.show {
    opacity: 1;
    transform: translateY(0);
}
.style1.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
    transition: all 0.6s cubic-bezier(0.54, 0.01, 0, 1);
}
.style1.split span.show {
    opacity: 1;
}

.style2.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
    transform: translateY(100px);
    transition: all 0.6s cubic-bezier(0.54, 0.01, 0, 1);
}
.style2.split span.show {
    opacity: 1;
    transform: translateY(0);
}

.style3.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
    transform: translateY(100px) translateX(-100px) rotate(360deg);
    transition: all 0.6s cubic-bezier(0.54, 0.01, 0, 1);
}
.style3.split span.show {
    opacity: 1;
    transform: translateY(0) translateX(0) rotate(0);
}

.style4.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
}
.style4.split span.show {
    opacity: 1;
    animation: lightSpeedIn 1s 1;
}

.style5.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
}
.style5.split span.show {
    opacity: 1;
    animation: zoomInDown 1s 1;
}

.style6.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
}
.style6.split span.show {
    opacity: 1;
    animation: flipInX 1s 1;
}

.style7.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
}
.style7.split span.show {
    opacity: 1;
    animation: flip 1s 1;
}

.style8.split span {
    opacity: 0;
    display: inline-block;
    min-width: 1vw;
}
.style8.split span.show {
    opacity: 1;
    animation: rubberBand 1s 1;
}

/* flipInX */
@keyframes flipInX {
    0% {
        -webkit-transform: perspective(400px) rotateX(90deg);
        transform: perspective(400px) rotateX(90deg);
        -webkit-animation-timing-function: ease-in;
        animation-timing-function: ease-in;
        opacity: 0
    }

    40% {
        -webkit-transform: perspective(400px) rotateX(-20deg);
        transform: perspective(400px) rotateX(-20deg);
        -webkit-animation-timing-function: ease-in;
        animation-timing-function: ease-in
    }

    60% {
        -webkit-transform: perspective(400px) rotateX(10deg);
        transform: perspective(400px) rotateX(10deg);
        opacity: 1
    }

    80% {
        -webkit-transform: perspective(400px) rotateX(-5deg);
        transform: perspective(400px) rotateX(-5deg)
    }

    to {
        -webkit-transform: perspective(400px);
        transform: perspective(400px)
    }
}

/* zoomInDown */
@keyframes zoomInDown {
    0% {
        opacity: 0;
        -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
        transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
        -webkit-animation-timing-function: cubic-bezier(.55, .055, .675, .19);
        animation-timing-function: cubic-bezier(.55, .055, .675, .19)
    }

    60% {
        opacity: 1;
        -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
        transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
        -webkit-animation-timing-function: cubic-bezier(.175, .885, .32, 1);
        animation-timing-function: cubic-bezier(.175, .885, .32, 1)
    }
}

/* lightSpeedIn */
@keyframes lightSpeedIn {
    0% {
        -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
        transform: translate3d(100%, 0, 0) skewX(-30deg);
        opacity: 0
    }

    60% {
        -webkit-transform: skewX(20deg);
        transform: skewX(20deg);
        opacity: 1
    }

    80% {
        -webkit-transform: skewX(-5deg);
        transform: skewX(-5deg)
    }

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

/* flip */
@keyframes flip {
    0% {
        -webkit-transform: perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn);
        transform: perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn);
        -webkit-animation-timing-function: ease-out;
        animation-timing-function: ease-out
    }

    40% {
        -webkit-transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg);
        transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg);
        -webkit-animation-timing-function: ease-out;
        animation-timing-function: ease-out
    }

    50% {
        -webkit-transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg);
        transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg);
        -webkit-animation-timing-function: ease-in;
        animation-timing-function: ease-in
    }

    80% {
        -webkit-transform: perspective(400px) scale3d(.95, .95, .95) translateZ(0) rotateY(0deg);
        transform: perspective(400px) scale3d(.95, .95, .95) translateZ(0) rotateY(0deg);
        -webkit-animation-timing-function: ease-in;
        animation-timing-function: ease-in
    }

    to {
        -webkit-transform: perspective(400px) scaleX(1) translateZ(0) rotateY(0deg);
        transform: perspective(400px) scaleX(1) translateZ(0) rotateY(0deg);
        -webkit-animation-timing-function: ease-in;
        animation-timing-function: ease-in
    }
}

/* rubberBand */
@keyframes rubberBand {
    0% {
        -webkit-transform: scaleX(1);
        transform: scaleX(1)
    }

    30% {
        -webkit-transform: scale3d(1.25, .75, 1);
        transform: scale3d(1.25, .75, 1)
    }

    40% {
        -webkit-transform: scale3d(.75, 1.25, 1);
        transform: scale3d(.75, 1.25, 1)
    }

    50% {
        -webkit-transform: scale3d(1.15, .85, 1);
        transform: scale3d(1.15, .85, 1)
    }

    65% {
        -webkit-transform: scale3d(.95, 1.05, 1);
        transform: scale3d(.95, 1.05, 1)
    }

    75% {
        -webkit-transform: scale3d(1.05, .95, 1);
        transform: scale3d(1.05, .95, 1)
    }

    to {
        -webkit-transform: scaleX(1);
        transform: scaleX(1)
    }
}

CSS 정리해보기

  • 각각의 css는 기본적으로 안보이다가 특정 class가 붙었을 때 보여지도록 구성했습니다.
  • 애니메이션 효과는 animate.css를 가져와 작업했습니다.

Javascript 살펴보기

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script>

<script>
    let text = document.querySelectorAll(".split");

    text.forEach(txt => {
        let splitText = txt.innerText;
        let splitWrap = splitText.split('').join("</span><span aria-hidden='true'>");
        txt.innerHTML = splitWrap = "<span aria-hidden='true'>" + splitWrap + "</span>"
        txt.setAttribute("aria-label", splitText);
    });

    function scroll(){
        let scrollTop = window.pageYOffset || window.screenY;

        document.querySelectorAll(".parallax__item").forEach(item => {
            if(scrollTop >= item.offsetTop - window.innerHeight/2){
                item.querySelector(".split").classList.add("show");
                item.querySelectorAll(".split span").forEach((spn, i) => {
                    setTimeout(() => {
                        spn.classList.add("show");
                    }, 50*i);
                });
            };
        });
        requestAnimationFrame(scroll);
    }
    scroll()

</script>

Javascript 정리해보기

  • class에 split이 있는 요소들을 전부 잡아 text 변수에 저장 후 forEach를 사용했습니다.
  • text 각각의 요소를 txt 변수로 사용하고
  • splitText에는 innerText를 사용하여 안에있는 텍스트 내용을 가져와 저장했습니다.
  • splitWrap에는 split과 join을 사용하여 한글자씩 분리하고 사이사이에 </span><span>을 추가해 합쳤습니다. (웹표준을 준수하기 위해 aria-hidden속성을 true로 했습니다.)
  • txt에 앞 뒤를 <span></span>태그로 감싼 splitWrap을 innerHTML 해주었습니다.
  • 각각의 글자에 aria-hidden=true 속성을 적용했기 때문에 txt에 aria-label를 사용하여 텍스트 내용을 알려주었습니다.

 

  • scroll함수
  • window의 scrollY 혹은 pageYoffSet 값을 scrollTop 변수에 저장합니다.
  • parallax__item 전체를 선택하여 forEach를 사용하고 각각의 요소를 item 변수로 사용합니다.
  • scrollTop값이 각각의 item의 offsetTop값에서 ( window의 innerHeight / 2 )를 뺀 값보다 크다면
  • item 안에있는 split의 classList에 show를 추가합니다.
  • split안에 있는 span에 다시 forEach를 사용하여 각각의 요소를 spn으로 사용합니다.
  • setTimeout을 사용하여 spn의 classList에 show를 추가하는데 각각의 시간을 50*index를 해주어 class에 show가 시간간격을 두고 순차적으로 생기도록 해주었습니다.
  • scroll함수를 requestAnimationFrame 메서드를 사용하여 1초에 60번씩 실행하도록 합니다.( 실시간으로 현재 scrollTop값을 구하기 위함 )
728x90
반응형