Fast Blinking Hello Kitty

JAVASCRIPT

포트폴리오에 사용하기좋은 효과 예제1

코른이되고싶은코린이 2023. 5. 6. 23:57

728x90

애니메이션 예제1

코드블럭

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=], initial-scale=1.0">
    <title>포트폴리토 메인페이지</title>
    <link href="https://fonts.googleapis.com/css2?family=Abel&display=swap" rel="stylesheet">
    
    <style>        
        @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.woff2';
            font-weight: normal;
            font-style: normal;
            src: url(fonts/PPNeueWorld-ExtendedThin.woff2) format('woff2');
            font-display: swap;
        }
        @font-face {
            font-family: 'PPNeueWorld-Regular.woff2';
            font-weight: normal;
            font-style: normal;
            src: url(fonts/PPNeueWorld-Regular.woff2) format('woff2');
            font-display: swap;
        }
        @font-face {
            font-family: 'PPNeueWorld-SemiCondensedUltrabold.woff2';
            font-weight: normal;
            font-style: normal;
            src: url(fonts/PPNeueWorld-SemiCondensedUltrabold.woff2) format('woff2');
            font-display: swap;
        }
        @font-face {
            font-family: 'PPNeueWorld-SemiExtendedBlack.woff2';
            font-weight: normal;
            font-style: normal;
            src: url(fonts/PPNeueWorld-SemiExtendedBlack.woff2) format('woff2');
            font-display: swap;
        }
        @font-face {
            font-family: 'PPNeueWorld-SuperCondensedLight.woff2';
            font-weight: normal;
            font-style: normal;
            src: url(fonts/PPNeueWorld-SuperCondensedLight.woff2) format('woff2');
            font-display: swap;
        }
        @font-face {
            font-family: 'PPNeueWorld-Thin.woff2';
            font-weight: normal;
            font-style: normal;
            src: url(fonts/PPNeueWorld-Thin.woff2) format('woff2');
            font-display: swap;
        }
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            width: 100%;
            height: 100vh;
            background-color: #0b130d;
            overflow: hidden;
        }
        /* header */
        #header {
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            color: #fff;
            display: flex;
            align-items: 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: bold;
            padding: 10px;
            font-size: 18px;
        }
        #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;
        }
        .text__inner > div em {
            font-style: normal;
            font-family: 'PPNeueWorld-Regular.woff2';
        }
        .text__inner > div.ti1 {
            font-family: 'PPNeueWorld-Thin.woff2';
        }
        .text__inner > div.ti2 {
            font-family: 'PPNeueWorld-Regular.woff2';
        }
        .text__inner > div.ti3 {
            font-family: 'PPNeueWorld-Thin.woff2';
        }
        .img__inner > img {
            position: absolute;
            width: 10vw;
            z-index: 2000;
        }
        .img__inner .ii1 {
            left: 45%;
            top: 50%;
            transform: translateY(-180%);
        }
        .img__inner .ii2 {
            left: 10%;
            top: 50%;
            transform: rotate(-10deg);
        }
        .img__inner .ii3 {
            left: 80%;
            top: 50%;
            transform: translateY(-30%) rotate(20deg);
        }
        #footer {
            position: fixed;
            left: 50%;
            bottom: 1vw;
            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;
        }
        #webgl {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100vh;
            z-index: 1;
        }
        #webgl iframe {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <header id="header">
        <h1>LeeEunJi's 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"><em>let's</em> inrtroduce</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://lee3ll.tistory.com/" target="_blank">lee3ll.tistory.com</a>
    </footer>
    <!-- footer -->

    <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);

            console.log(splitWrap)
        });

        //메인셋팅
        gsap.set(".text__inner .ti1", {opacity: 0, y:"10vh"});
        gsap.set(".text__inner .ti2 span", {opacity: 0, x: 500, scale:6, rotation: 5, display: "inline-block", minWidth: "1.4vw"});
        gsap.set(".text__inner .ti3", {opacity: 0, y:"-10vh"});
        gsap.set(".img__inner .ii1", {opacity: 0, rotation:360, y: -210, ease: Power3.easeInOut});
        gsap.set(".img__inner .ii2", {opacity: 0, rotation:360, ease: Power3.easeInOut});
        gsap.set(".img__inner .ii3", {opacity: 0, rotation:360, ease: Power3.easeInOut});
        gsap.set("#header", {y:-100});
        gsap.set("#footer", {bottom:-100});
        gsap.set("#webgl", {opacity: 0});
        
        //메인 애니메이션
        setTimeout(()=>{
            let tl = gsap.timeline();

            tl.to(".text__inner .ti2 span", {opacity:1, x:0, scale: 1, rotation: 0, duration: 0.6, stagger: 0.1, ease: Power3.easeInOut})
            tl.to(".text__inner .ti1", {opacity:1, y:0, duration: 0.5, ease: Circ.easeOut}, "hwang +=1")
            tl.to(".text__inner .ti3", {opacity:1, y:0, duration: 0.5, ease: Circ.easeOut}, "hwang +=1")
            tl.to(".img__inner .ii1", {duration: 0.5, rotation:0, opacity: 1, scale: 1})
            tl.to(".img__inner .ii2", {duration: 0.5, rotation:-10, opacity: 1, scale: 1})
            tl.to(".img__inner .ii3", {duration: 0.5, rotation:20, opacity: 1, scale: 1})
            tl.to("#header", {duration: 0.5, y:0, ease: Power3.easeInOut}, "end")
            tl.to("#footer", {duration: 0.5, bottom: "1vw", ease: Power3.easeInOut}, "end")
            tl.to("#webgl", {duration: 1, opacity: 1})
        }, 2000)
        
    </script>
</body>
</html>

보충설명

✨ 이 코드는 GreenSock Animation Platform (GSAP) 라이브러리를 웹페이지에 추가하는 코드입니다.

GSAP은 HTML, CSS, SVG 및 JavaScript 기반 웹 애니메이션을 만들기 위해 사용되는 강력하고 유연한 JavaScript 애니메이션 라이브러리입니다. 외부 라이브러리인 GSAP을 가져와서 사용하기 위해, 라이브러리 파일이 위치한 경로를 지정하여 웹 페이지에 추가합니다. 

 

//글씨 분리하기

✨ 문서 내의 모든 split 클래스를 가진 요소를 찾아서, 그 요소의 텍스트를 하나씩 나눈 후, 각각을 <span> 태그로 감싸는 기능을 합니다. 이 기능은 forEach 메소드를 사용하여, 문서 내의 모든 .split 요소를 순회하며 수행됩니다. 각각의 .split 요소에 대해, innerText 속성을 사용하여 해당 요소의 텍스트를 가져온 후, split() 함수를 이용하여 텍스트를 하나씩 나눕니다.

 

✨ join() 함수를 사용하여 각 문자들을 </span><span aria-hidden='true'> 로 연결하여 하나의 문자열로 만듭니다. 이렇게 만들어진 문자열 앞뒤에 <span aria-hidden='true'> 태그를 추가하여 요소 내부 HTML 코드로 만든 후, 해당 요소의 innerHTML 속성에 할당합니다.

 

✨ setAttribute 함수를 이용하여, desc 요소의 aria-label 속성을 텍스트 내용으로 설정합니다. aria-label 속성은 시각장애인을 포함한 일부 사용자들에게 정보를 전달하는데 사용됩니다.

 

//메인셋팅

✨ .text__inner .ti1, .text__inner .ti2 span, .text__inner .ti3: 텍스트 요소의 초기 상태를 설정합니다. .ti1은 y축으로 10vh 만큼 이동하고 투명도는 0으로 설정됩니다. .ti2 span은 x축으로 500만큼 이동하고 scale값은 6, rotation값은 5도, display 속성은 inline-block, minWidth값은 1.4vw로 설정됩니다. 마지막으로, .ti3는 y축으로 -10vh만큼 이동하고 투명도는 0으로 설정됩니다.

 

✨.img__inner .ii1, .img__inner .ii2, .img__inner .ii3: 이미지 요소의 초기 상태를 설정합니다. .ii1은 rotation값이 360도이고, y축으로 -210px만큼 이동하며, 이동 애니메이션의 ease값은 Power3.easeInOut으로 설정됩니다. .ii2와 .ii3는 .ii1과 비슷한 방식으로 초기 상태가 설정됩니다.

 

✨ #header, #footer, #webgl: 각 요소의 초기 상태를 설정합니다. #header와 #footer는 각각 y와 bottom 값이 -100으로 설정됩니다. 마지막으로, #webgl 요소는 초기에 투명도가 0으로 설정됩니다.

 

//메인 애니메이션

✨ setTimeout 함수는 2초(2000ms) 후에 내부의 코드를 실행합니다.

그리고 나서 gsap.timeline() 메소드를 사용하여 GSAP (GreenSock Animation Platform) 라이브러리에서 제공하는 타임라인을 생성합니다.

 

✨ 타임라인에 등록된 애니메이션은 순차적으로 실행되며, 각 애니메이션은 앞선 애니메이션의 종료시점을 기준으로 상대적인 시간을 가집니다.

tl.to 메소드를 사용하여 각 요소들의 애니메이션 효과를 지정합니다. 예를 들어, .text__inner .ti2 span 클래스의 요소를 선택하여 0.6초 동안 opacity, x, scale, rotation 속성을 변경하여 애니메이션을 적용합니다.

 

✨ stagger 옵션을 사용하면 동일한 애니메이션 효과를 가진 요소들을 지정한 간격으로 순차적으로 실행할 수 있습니다.

애니메이션이 순차적으로 실행될 때, 각 애니메이션의 시작 시간을 지정할 수 있습니다. 이 코드에서는 hwang +=1 표기법을 사용하여 ti1 클래스와 ti3 클래스 요소들의 애니메이션 시작 시간을 이전 애니메이션 종료 시간보다 1초 뒤로 지연시킵니다.

 

✨이미지 요소들에 대한 애니메이션을 등록하고, #header와 #footer 요소들의 애니메이션을 등록합니다. 

✨ #webgl 요소의 opacity 값을 1로 변경하여 애니메이션을 적용합니다.