애니메이션 예제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로 변경하여 애니메이션을 적용합니다.