본문 바로가기
Tutorial/GSAP

11. GSAP Parallax Effect : 메뉴 숨기기 효과

by @webstoryboy 2023. 6. 20.
Tutorial/webd

GSAP 패럴랙스 이펙트 : 메뉴 숨기기 효과

by @webs 2023. 06. 01.
11
GSAP Parallax Effect : 메뉴 숨기기 효과
난이도 중간

소개

안녕하세요! 웹스토리보이입니다. 이번에는 메뉴를 숨기는 효과를 만들어보겠습니다. 스크롤을 내리면 메뉴는 위로 올라가고, 스크롤을 올리면 메뉴는 다시 나타나는 형태입니다. GSAP를 이용하니 퀄리티 애니메이션을 구현할 수 있는 점이 좋네요! 소스로 새로운 속성들이 나오기는 하나 그렇게 어렵지는 않으니 같이 잘 따라 해봅시다. 그럼 시작해볼께요! 💩

1. 기본 구조 만들기

1-1. 준비하기

GSAP를 배우는 시간이기 때문에 HTML/CSS 코딩은 생략하겠습니다. 기본 코딩은 복사해서 사용하겠습니다. 우선 웹폰트를 설정하고 GSAP에서 필요한 파일을 미리 셋팅해 놓겠습니다. GSAP는 자주 업데이트가 되기 때문에 제일 최선 버전을 사용하는게 좋습니다.

<!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>GSAP Scroll Effect</title>

    <!-- 웹폰트 설정 -->
    <link href="https://webfontworld.github.io/NexonLv1Gothic/NexonLv1Gothic.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Lato:wght@100&display=swap" rel="stylesheet">
</head>
<body>

    <!-- GSAP 라이브러리 설정 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/ScrollTrigger.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.1/ScrollToPlugin.min.js"></script>
</body>
</html>

1-2. 기본 셋팅하기

소스는 그대로 복사해서 사용하겠습니다.

<!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>GSAP Scroll Effect</title>

    <link href="https://webfontworld.github.io/NexonLv1Gothic/NexonLv1Gothic.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Lato:wght@100&display=swap" rel="stylesheet">
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        a {
            color: #fff;
            text-decoration: none;
        }
        body {
            color: #fff;
            font-family: "NexonLv1Gothic";
            font-weight: 300;
            background-color: #333;
        }
        #parallax__title {
            position: fixed;
            left: 20px;
            top: 20px;
            z-index: 1000;
        }
        #parallax__title h1 {
            font-size: 30px;
            border-bottom: 1px dashed #fff;
            margin-bottom: 10px;
            padding-bottom: 5px;
            font-weight: 400;
            display: inline-block;
        }
        #parallax__title p {
            font-size: 16px;
        }
        #parallax__title ul {
            margin-top: 10px;
        }
        #parallax__title li {
            display: inline;
        }
        #parallax__title li a {
            width: 20px; 
            height: 20px;
            border-radius: 50%;
            border: 1px dashed #fff;
            display: inline-block;
            text-align: center;
            line-height: 20px;
            font-size: 12px;
        }
        #parallax__title li.active a {
            background: #fff;
            color: #000;
        }
        #parallax__nav {
            position: fixed;
            right: 20px;
            top: 20px;
            z-index: 1000;
            background-color: rgba(0,0,0,0.4);
            padding: 15px 20px;
            border-radius: 50px;
            text-align: center;
        }
        #parallax__nav li {
            list-style: none;
            display: inline;
        }
        #parallax__nav li a {
            display: inline-block;
            width: 30px; 
            height: 30px;
            padding: 5px;
            text-align: center;
            line-height: 30px;
            transition: all 0.3s;
        }
        #parallax__nav li a.active {
            background: #fff;
            color: #000;
            border-radius: 30px;
        }

        /* parallax__cont */
        #parallax__cont {
            max-width: 1600px;
            width: 98%;
            margin: 0 auto;
        }
        .parallax__item {
            width: 1000px;
            max-width: 70vw;
            margin: 30vw auto;
            text-align: left;
            margin-right: 0;
            position: relative;
            padding-top: 15vw;
        }
        .parallax__item:nth-child(even) {
            margin-left: 0;
            text-align: right;
        }
        .parallax__item__num {
            font-size: 35vw;
            position: absolute;
            left: -5vw;
            top: -13vw;
            opacity: 0.07;
            font-family: "Lato";
            font-weight: 100;
        }
        .parallax__item:nth-child(even) .parallax__item__num {
            left: auto;
            right: -5vw;
        }
        .parallax__item__title {
            padding-bottom: 5px;
            font-weight: 400;
        }
        .parallax__item__imgWrap {
            width: 100%;
            padding-bottom: 56.25%;
            background: #000;
            position: relative;
            overflow: hidden;
        }
        .parallax__item__img {
            position: absolute;
            left: -5%; 
            top: -5%;
            width: 110%;
            height: 110%;
            background-repeat: no-repeat;
            background-position: center center;
            background-size: cover;
            filter: saturate(0%);
            transition: all 1s;
        }
        .parallax__item__img:hover {
            filter: saturate(100%);
            transform: scale(1.025);
        }
        #section1 .parallax__item__img {
            background-image: url(asswts/img/images01@2.jpg);
        }
        #section2 .parallax__item__img {
            background-image: url(asswts/img/images02@2.jpg);
        }
        #section3 .parallax__item__img {
            background-image: url(asswts/img/images03@2.jpg);
        }
        #section4 .parallax__item__img {
            background-image: url(asswts/img/images04@2.jpg);
        }
        #section5 .parallax__item__img {
            background-image: url(asswts/img/images05@2.jpg);
        }
        #section6 .parallax__item__img {
            background-image: url(asswts/img/images06@2.jpg);
        }
        #section7 .parallax__item__img {
            background-image: url(asswts/img/images07@2.jpg);
        }
        #section8 .parallax__item__img {
            background-image: url(asswts/img/images08@2.jpg);
        }
        #section9 .parallax__item__img {
            background-image: url(asswts/img/images09@2.jpg);
        }
        .parallax__item__desc {
            font-size: 4vw;
            line-height: 1.4;
            margin-top: -5vw;
            margin-left: -4vw;
            z-index: 100;
            position: relative;
            word-break: keep-all;
        }
        .parallax__item:nth-child(even) .parallax__item__desc {
            margin-left: auto;
            margin-right: -4vw;
        }
    </style>
</head>
<body>
    <header id="parallax__title">
        <h1>GSAP Parallax Effect11</h1>
        <p>GSAP scrollTrigger - 메뉴 숨기기 효과</p>
        <ul>
            <li><a href="gsap01.html">1</a></li>
            <li><a href="gsap02.html">2</a></li>
            <li><a href="gsap03.html">3</a></li>
            <li><a href="gsap04.html">4</a></li>
            <li><a href="gsap05.html">5</a></li>
            <li><a href="gsap06.html">6</a></li>
            <li><a href="gsap07.html">7</a></li>
            <li><a href="gsap08.html">8</a></li>
            <li><a href="gsap09.html">9</a></li>
            <li><a href="gsap10.html">10</a></li>
            <li class="active"><a href="gsap11.html">11</a></li>
            <li><a href="gsap12.html">12</a></li>
            <li><a href="gsap13.html">13</a></li>
            <li><a href="gsap14.html">14</a></li>
            <li><a href="gsap15.html">15</a></li>
        </ul>
    </header>
    <!-- //parallax__title  -->

    <nav id="parallax__nav">
        <ul>
            <li><a href="#section1" class="active">s1</a></li>
            <li><a href="#section2">s2</a></li>
            <li><a href="#section3">s3</a></li>
            <li><a href="#section4">s4</a></li>
            <li><a href="#section5">s5</a></li>
            <li><a href="#section6">s6</a></li>
            <li><a href="#section7">s7</a></li>
            <li><a href="#section8">s8</a></li>
            <li><a href="#section9">s9</a></li>
        </ul>
    </nav>
    <!-- //parallax__nav -->

    <main id="parallax__cont">
        <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">높은 목표를 세우고, 스스로 채찍질 한다.</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">결과도 중요하지만, 과정을 더 중요하게 생각한다.</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">매 순간에 최선을 다하고, 끊임없이 변화한다.</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">모든 일에는 기본을 중요하게 생각한다.</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">열정을 잃지 않고 실패에서 실패로 걸어가는 것이 성공이다.</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">천 마디 말보단 하나의 행동이 더 값지다.</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">조그만 성공에 만족하지 않으며, 방심을 경계한다.</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">나는 내가 더 노력할수록 운이 더 좋아진다는 걸 발견했다.</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">꿈이 있다면, 그 꿈을 잡고 절대 놓아주지마라.</p>
        </section>
        <!-- //section9 -->
    </main>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/ScrollTrigger.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.1/ScrollToPlugin.min.js"></script>
    <script>
        
    </script>
</body>
</html>

2. 스크립트 작업하기

2-1. 작업하기

소스는 비교적 간단하지만, 여러가지 속성이 많이 들어가 있습니다. 먼저, showNav라는 변수를 선언합니다. 이 변수는 GSAP의 from 메서드를 사용하여 #parallax__nav라는 요소에 대해 애니메이션을 생성합니다. 애니메이션은 yPercent 속성을 이용하여 요소를 수직으로 -200%만큼 이동시킵니다. paused 속성은 애니메이션을 초기에 일시 정지 상태로 설정합니다. duration 속성은 애니메이션의 지속 시간을 0.2초로 설정합니다. 마지막으로 progress 메서드를 사용하여 애니메이션의 진행 상태를 1로 설정합니다.

다음으로, ScrollTrigger.create 메서드를 사용하여 스크롤 트리거를 생성합니다. start 속성은 트리거의 시작 지점을 "top top"으로 설정합니다. end 속성은 트리거의 끝 지점을 99999로 설정하여 페이지의 끝까지 트리거가 유지되도록 합니다. onUpdate 콜백 함수는 스크롤 트리거가 업데이트될 때마다 호출되며, self 매개변수를 통해 트리거 자체에 접근할 수 있습니다. 콜백 함수 내부에서는 self.direction 속성을 확인하여 스크롤 방향을 확인하고, -1이면 showNav 애니메이션을 실행하고 그렇지 않으면 반대 방향으로 재생시킵니다.

#parallax__nav 요소가 스크롤의 상단에 도달하면 나타나고, 스크롤을 아래로 내릴 때 숨겨집니다. 스크롤 트리거의 범위가 페이지의 끝까지로 설정되어 있으므로, 스크롤을 위로 올리면 항상 내비게이션 바가 나타납니다.

const showNav = gsap.from("#parallax__nav", { 
    yPercent: -200,
    paused: true,
    duration: 0.2
}).progress(1);

ScrollTrigger.create({
    start: "top top",
    end: 99999,
    onUpdate: (self) => {
        self.direction === -1 ? showNav.play() : showNav.reverse()
    }
});

3. 마무리

이렇게 해서 메뉴 숨기기 효과도 마무리 됐습니다. 조금 복잡하긴 하지만, 이해가 안된다면 그냥 복사해서 써도 무관합니다. 그러다 보면서 수정하고 다시 쓰고, 하면 이해가 되기 시작하고, 조금씩 이해가 되기 시작합니다. 스크립트는 한번에 이해되고, 넘어가는 언어가 아닙니다. 차곡차곡 조금씩 이해도가 쌓이다 보면 어느새 자기것이 되는 것을 확인할 수 있습니다. 그러니 지금 이해안된다고 포기하지 말고, 끝까지 완성한 다음에 다음에 보시면 이해가 될것입니다. 화이팅🤭


예제 목록

댓글