Lumpy Space Princess - Adventure Time

JAVASCRIPT

Mouse Effect 02 - GSAP를 이용해서 마우스를 따라다니기에 대해서 알아보자

jongyung 2023. 3. 21. 12:29

“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90

GSAP를 이용해서 마우스를 따라다니는 효과에 대해서 알아보겠습니다.

The GreenSock Animation Platform(gsap) 를 사용했는데요, 프론트엔드 개발자와 디자이너들이 쉽게 사용할 수 있는 타임라인 기반의 애니메이션 자바스크립트 라이브러리입니다.

자바스크립트 라이브러리란?
쉽게 말해, 자주 사용되지만 일일히 구현하기엔 까다롭거나 불편한 자바스크립트의 코드의 특정 기능을 기성품으로 만들어 묶어놓은 패키지 같은 것을 말합니다.
예를 들자면 가구를 만들때 경첩이나 슬라이드 같은 하드웨어는 만들어진 것을 사서 조립하는 것과 비슷한 개념입니다.

 

body 의 main 부분과 style 그리고 script 부분으로 나눠서 설명하겠습니다.

body 의 main

<main id="main">
    <div class="mouse__wrap">
        <div class="mouse__cursor"></div>
        <div class="mouse__cursor2"></div>
        <div class="mouse__text">       
            <p>One needs to be <span>slow</span> to form convictions,but once formed they must be defended against <span>heaviest odds</span>.</p> 
            <p>신념을 형성할 때는 <span>신중</span>해야 하지만 신념이 형성된 후에는 <span>어떤 어려움</span>에서도 지켜야 한다.</p>       
        </div>
    </div>        
</main>

body 는 간단합니다.

조정을 해 줄 부분들에 class 를 정하고, 내용을 입력합니다.

강조할 부분은 span 태그로 감싸서 효과를 줍니다.

style 

<style>
    .mouse__wrap {
        cursor: none;
    }
    .mouse__text {
        width: 100%;
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
        overflow: hidden;
    }
    .mouse__text p {
        font-size: 2vw;
        line-height: 1.5;
    }
    .mouse__text p span {
        color: rgb(112, 191, 178);
        font: bold;
    }
    .mouse__text p :last-child {
        font-size: 3vw;
    }
    .mouse__cursor {
        position: absolute;
        left: 0;
        top: 0;
        width: 10px;
        height: 10px;
        z-index: 9999;
        border-radius: 50%;
        background-color: rgba(255, 255, 255, 0.3);
        user-select: none;
        pointer-events: none;
        transition: transform 0.3s;
    }
    .mouse__cursor2 {
        position: absolute;
        left: 0;
        top: 0;
        width: 30px;
        height: 30px;
        z-index: 9998;
        border-radius: 50%;
        background-color: rgba(255, 255, 255, 0.5);
        user-select: none;
        pointer-events: none;
        transition: transform 0.3s;
    }
    .mouse__cursor.active {
        transform: scale(0);
    }
    .mouse__cursor2.active {
        transform: scale(5);
        background-color: rgba(rgb(139, 96, 96), rgb(92,rgb(44, 44, 73), 92), rgb(74, 74, 79), alpha);
    }
    .mouse__cursor.active2 {
        transform: scale(1);
        background-color: #d9a1a1;
    }
    .mouse__cursor2.active2 {
        transform: scale(6);
        background-color: #df74747d;
    }
    .mouse__cursor.active3 {
        transform: scale(2);
        background-color: #c7d883;
    }
    .mouse__cursor2.active3 {
        transform: scale(7);
        background-color: #c1dc5786;
    }
    .img {
        background-color: #817e7e;
    }
</style>

user-select : none 은 텍스트 영역이 클릭 및 드래그로 선택되지 않게 하고,

pointer-events : none 은 HTML 요소에 정의된 클릭, 상태(hover,active등), 커서 옵션들이 비활성화합니다.

이 두 가지의 속성 값들로 인해 마우스를 글자 위에 올려두면 원형을 유지하며 클릭의 동작은 하지 않도록 했습니다.

 

transform-origin 속성은 위의 transform 속성인 scale(), rotate(), translate(), skew()들을 한번씩 연습해 보았다면, 지정 요소의 중심을 기준으로 동작한다는 것을 알 수 있을 것 입니다.
하지만 transform-origin 을 사용하면 지정 요소의 기준점을 변경할 수 있습니다.

 

z-index 속성은 위치 지정 요소와, 그 자손 또는 하위 플렉스 아이템의 Z축 순서를 지정합니다.

더 큰 z-index 값을 가진 요소가 작은 값의 요소 위를 덮습니다.

position 속성을 이용하면 요소를 겹치게 놓을 수 있습니다.

이때 요소들의 수직 위치를 z-index 속성으로 정합니다.

값은 정수이며, 숫자가 클 수록 위로 올라오고, 숫자가 작을 수록 아래로 내려갑니다.

 

position: absolute 는 요소를 일반적인 문서 흐름에서 제거합니다.

가장 가까운 위치에 있는 조상 요소를 기준으로 배치합니다.
조상 요소 위치를 기준으로 위쪽(top), 아래쪽(bottom), 왼쪽(left), 오른쪽(right)에서 얼마만큼 떨어질 지 결정합니다.
조상 중 position을 가진 요소가 없다면 초기 컨테이닝 블록(<body>요소)를 기준으로 삼습니다. 
문서 상 원래 위치를 잃어버리고, 아래에 있는 div가 해당 자리를 차지합니다.

script 

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script>
<script>
    //선택자
    const cursor = document.querySelector(".mouse__cursor");
    const cursor2 = document.querySelector(".mouse__cursor2");

    //커서 좌표값 할당
    window.addEventListener("mousemove", e => {
        // cursor.style.left = e.pageX + "px";
        // cursor.style.top = e.pageY + "px";
        // cursor2.style.left = e.pageX + "px";
        // cursor2.style.top = e.pageY + "px";

        //gsap
        gsap.to(cursor,{duration: 0.3, left: e.pageX -5, top: e.pageY -5});
        gsap.to(cursor2,{duration: 0.8, left: e.pageX -15, top: e.pageY -15});

        //오버 효과
        // document.querySelector(".mouse__text span").addEventListener("mouseenter", () => {
        //     cursor.classList.add("active");
        //     cursor2.classList.add("active");
        // });
        // document.querySelector(".mouse__text span").addEventListener("mouseleave", () => {
        //     cursor.classList.remove("active");
        //     cursor2.classList.remove("active");
        // });


        document.querySelectorAll(".mouse__text span").forEach((span) => {
            span.addEventListener("mouseenter", () => {
                cursor.classList.add("active");
                cursor2.classList.add("active");
            });

            span.addEventListener("mouseleave", () => {
                cursor.classList.remove("active");
                cursor2.classList.remove("active");
            });

        });
        //메일, 제목 부분
        document.querySelector("#footer a").addEventListener("mouseenter", () => {
            cursor.classList.add("active2");
            cursor2.classList.add("active2");
        });
        document.querySelector("#footer a").addEventListener("mouseleave", () => {
            cursor.classList.remove("active2");
            cursor2.classList.remove("active2");
        });
        document.querySelector("#header").addEventListener("mouseenter", () => {
            cursor.classList.add("active3");
            cursor2.classList.add("active3");
        });
        document.querySelector("#header").addEventListener("mouseleave", () => {
            cursor.classList.remove("active3");
            cursor2.classList.remove("active3");
        });
    });    
</script>

pageX 는 X의 좌표값 페이지 기준이고, pageY 는 Y의 좌표값 페이지 기준입니다.

transition-duration로 transition이 끝날 때까지 걸리는 시간을 정합니다.

transition 동안 모든 속성에 적용하는 단일 지속 시간을 명시하거나, 다른 주기로 각 속성이 트랜지션하게 하는 여러 지속 시간을 명시할 수 있습니다.

마우스가 움직일 때 조금 느리게 뒤따라오는 원형을 보면 알 수 있습니다.

 

이번에도 반복되는 함수식은 querySelectorAll 과 forEach 메서드를 써서 간추렸습니다.