Winnie The Pooh Bear 포트폴리오 메인페이지 만들어보기(gsap)

배움기록/JAVASCRIPT

포트폴리오 메인페이지 만들어보기(gsap)

코딩은 처음이라 2023. 5. 3. 22:33

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

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90
반응형

포트폴리오 메인페이지 만들어보기(gsap)

 

 

 

 

💜 포트폴리오 메인페이지

코드 보기 / 완성 화면

 

 

폰트CSS

@font-face {
    font-family: 'PPNeueWorld-CondensedRegular';
    font-weight: normal;
    font-style: normal;
    src: url('fonts/PPNeueWorld-CondensedRegular.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: 'PPNeueWorld-ExtendedThin';
    font-weight: normal;
    font-style: normal;
    src: url('fonts/PPNeueWorld-ExtendedThin.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: 'PPNeueWorld-Regular';
    font-weight: normal;
    font-style: normal;
    src: url('fonts/PPNeueWorld-Regular.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: 'PPNeueWorld-SemiCondensedUltrabold';
    font-weight: normal;
    font-style: normal;
    src: url('fonts/PPNeueWorld-SemiCondensedUltrabold.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: 'PPNeueWorld-SemiExtendedBlack';
    font-weight: normal;
    font-style: normal;
    src: url('fonts/PPNeueWorld-SemiExtendedBlack.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: 'PPNeueWorld-SuperCondensedLight';
    font-weight: normal;
    font-style: normal;
    src: url('fonts/PPNeueWorld-SuperCondensedLight.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: 'PPNeueWorld-Thin';
    font-weight: normal;
    font-style: normal;
    src: url('fonts/PPNeueWorld-Thin.woff2') format('woff2');
    font-display: swap;
}

 

디자인에서 폰트가 가장 중요하기 때문에

여러가지 사용할 폰트를 @font-face를 사용해 각각 불러와줬습니다.

font-family속성을 이용해 각각의 폰트에 이름을 지정해주고,  스타일을 설정해줬습니다.

모든 폰트 파일은 WOFF2형식으로 가져왔습니다.

 

*WOFF2는 Web Opne Font Format 2의 약어로 

웹에서 사용되는 폰트 형식 중 하나인데

TTF, OTF 형식의 폰트 파일을 압축해 더 작은 파일크기를 제공하면서 웹에서 더 빠르게 로드될 수 있도록 하는 형식입니다.

 

 

HTML

<body>
<header id="header">
    <h1>HHH PORTFOLIO</h1>
    <nav>
        <ul>
            <li><a href="#">work</a></li>
            <li><a href="#">about</a></li>
        </ul>
    </nav>
</header>
<!-- //header -->

<main id="main">
    <div class="text__inner">
        <div class="ti1">Let's <em>introduce</em></div>
        <div class="ti2 split">frontend developer's</div>
        <div class="ti3"><em>all</em> works <em>of</em> portfolio</div>
    </div>
    <div class="img__inner">
        <img class="ii1" src="img/figure01.png" alt="이미지1">
        <img class="ii2" src="img/figure02.png" alt="이미지2">
        <img class="ii3" src="img/figure03.png" alt="이미지3">
    </div>
    <div id="webgl">
        <iframe src="three.html" frameborder="0"></iframe>
    </div>
</main>
<!-- //main -->

<footer id="footer">
    <a href="https://mi-1119.tistory.com/" target="_blank">mi-1119.tistory.com</a>
</footer>
<!-- //footer -->

header, main, footer로 나누어줬습니다.

 

폰트를 각각 지정해줄거기 때문에 

em태그로 나눠줬습니다.

 

iframe을 사용해 배경으로 들어갈 three.html을 로드해 사용해줬습니다.

https://wiss.tistory.com/502

배경은 이 링크를 통해 가져왔습니다.

코드는 링크로 확인해주세요!

 

 

 

CSS

    /* header */
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

    body {
        width: 100%;
        height: 100vh;
        background-color: #0b130d;
        overflow: hidden;
    }

    #header {
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
        display: flex;
        align-items: flex-end;
        justify-content: space-between;
        padding: 10px 20px;
        font-family: 'Abel';
        z-index: 1000;
    }

    #header h1 {
        font-weight: normal;
        color: #D2E3C0;
        font-size: 28px;
    }

    #header nav li {
        list-style: none;
        display: inline-block;
    }

    #header nav li a {
        color: #D2E3C0;
        text-transform: uppercase;
        font-weight: normal;
        padding: 10px;
        font-size: 18px;
    }

    #footer {
        position: fixed;
        left: 50%;
        bottom: 1vh;
        transform: translateX(-50%);
        z-index: 1000;
    }

    #footer a {
        color: #fff;
        font-family: 'Abel';
        text-decoration: none;
    }

    #footer a:hover {
        text-decoration: underline;
        text-underline-position: under;
    }

    #main {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        height: 100vh;
        position: relative;
    }

    .text__inner {
        text-align: center;
        color: #D2E3C0;
        position: relative;
        z-index: 3000;
    }

    .text__inner>div {
        font-size: 8vw;
        line-height: 1.2;
    }

    .text__inner>div.ti1 {
        font-family: 'PPNeueWorld-SemiCondensedUltrabold';
    }

    .text__inner>div.ti1 em {
        font-family: 'PPNeueWorld-Thin';
        font-style: normal;
    }

    .text__inner>div.ti2 {
        font-size: 80px;
        font-family: 'PPNeueWorld-SemiExtendedBlack';
    }

    .text__inner>div.ti3 {
        font-family: 'PPNeueWorld-SemiCondensedUltrabold';
    }

    .text__inner>div.ti3 em {
        font-family: 'PPNeueWorld-ExtendedThin';
    }

    .img__inner>img {
        position: absolute;
        width: 10vw;
        z-index: 2000;
    }

    .img__inner .ii1 {
        left: 45%;
        top: 30%;
        transform: translateY(-200%);
    }

    .img__inner .ii2 {
        left: 10%;
        top: 55%;
        transform: translateY(-180%);
    }

    .img__inner .ii3 {
        left: 85%;
        top: 55%;
        transform: translateY(-180%);
    }

    #webgl {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100vh;
        z-index: 1;
    }

    #webgl iframe {
        width: 100%;
        height: 100%;
    }

나눠줬던 태그안에 폰트를 각각 지정해줬습니다.

 

body에 overflow : hidden을 설젖ㅇ해 페이지가 넘치는 경우 스크롤바가 표시되지 않도록 해줬습니다.

header, footer에 position : fixed를 사용해 페이지 위치에 고정시켜줬습니다.

 

 

gsap

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script>
<script>
    //글씨 분리하기
    document.querySelectorAll(".split").forEach(desc => {
        let splitText = desc.innerText;
        let splitWrap = splitText.split('').join("</span><span aria-hidden:'true'>");
        splitWrap = "<span aria-hidden:'true'>" + splitWrap + "</span>";
        desc.innerHTML = splitWrap;
        desc.setAttribute("aria-label", splitText);
    });

    //메인 기본세팅
    gsap.set(".text__inner .ti1", { opacity: 0, y: "10vh" });
    gsap.set(".text__inner .ti2 span", { opacity: 0, x: 500, scale: 4, display: "inline-block", minWidth: "1.4vw" });
    gsap.set(".text__inner .ti3", { opacity: 0, y: "-10vh" });
    gsap.set(".img__inner .ii1", { opacity: 0, scale: 10, rotation: 360 });
    gsap.set(".img__inner .ii2", { opacity: 0, scale: 10, rotation: 360 });
    gsap.set(".img__inner .ii3", { opacity: 0, scale: 10, rotation: 360 });
    gsap.set("#header", { opacity: 0, scale: 10 });
    gsap.set("#footer", { bottom: -100 });

    gsap.set("#webgl", { opacity: 0 });

    //메인 애니메이션
    setTimeout(() => {
        let tl = gsap.timeline();     //delay필요없이 순차적으로 가능(콜백함수)

        tl.to(".text__inner .ti2 span", { opacity: 1, x: 0, scale: 1, duration: 0.6, stagger: 0.1, ease: Power3.easeInOut })
        tl.to(".text__inner .ti1", { opacity: 1, y: 0, duration: 0.5, ease: Circ.easeOut }, "hhh +=0.5")  //"hhh"추가로 같이 실행되게할수있음
        tl.to(".text__inner .ti3", { opacity: 1, y: 0, duration: 0.5, ease: Circ.easeOut }, "hhh +=0.5")
        tl.to(".img__inner .ii1", { opacity: 1, scale: 1, duration: 0.6, rotation: 0 })
        tl.to(".img__inner .ii2", { opacity: 1, scale: 1, duration: 0.6, rotation: 0 })
        tl.to(".img__inner .ii3", { opacity: 1, scale: 1, duration: 0.6, rotation: 0 })
        tl.to("#header", { opacity: 1, scale: 1, duration: 0.6 });
        tl.to("#footer", { duration: 1, bottom: "1vw", ease: Power3.easeInOut }, "end");
        tl.to("#webgl", { duration: 1, opacity: 1 });
    }, 3000);
</script>

GSAP 라이브러리를 사용해 웹 페이지에서 애니메이션을 추가하는 코드입니다.

 

innerText를 사용해 선택한 요소의 텍스트를 가져온 다음, split()를 사용해 텍스트를 한글자씩 분리해줍니다.

그런 다음 join()을 사용해 분리된 글자들을 다시 하나의 문자열로 결합하면  </span><span aria-hidden:'true'>가 추가됩니다.

그런 다음 aplitWrap 문자열 앞뒤에 <span aria-hidden:'true'>추가해 span요소로 감싸고 innerHTML을 사용해 선택한 요소의 내용을 변경해 setAttribute()를 사용해 aria-label속성에 선택한 요소의 텍스트를 추가합니다.

 

gsap.set()을 사용해 초기 상태를 설정해주고, setTimeout()함수를 사용해 3초 후에 애니메이션을 시작합니다.

콜백 함수를 호출해 지연을 추가합니다.

 

이어서 gsap.timeline() 으로 타임라인 객체를 만들어 각 요소의 애니메이션을 순차적으로 실행할 수 있도록 합니다. tl.to()함수를 사용해 애니메이션을 추가해, 각 애니메이션 실행 시간(duration), easing함수(sase), delay시간(stagger)등을 설정해줍니다. tl.to()함수의 마지막 파라미터인 hhh += 0.5 는 hhh라는 라벨로 추가해 이전 애니메이션 종료 후 0.5초 뒤에 실행하게 합니다.

 

마지막으로 각 요소들의 애니메이션이 모두 끝난 후 setTimeout()함수에 설정한 1초 후에 #webgl 요소의 투명도를 1로 변경해 페이지에 표시합니다.

반응형