👉 사이트명 : 엔터프라이즈블록체인
👉 작업기간 : 3일
👉 사용언어 : HTML5, CSS3, Jquery
👉 라이브러리 : GSAP
👉 분류 : PC 세미 반응형 웹사이트
👉 URL : https://seona-cha.github.io/enterprise
✔️ 모션의 분석과 이해
✔️ GSAP + ScrollTrigger를 활용한 애니메이션 구현
✔️ Video Background로 사용
✔️ Top버튼 위치 변화
✔️ 한 방향으로 계속 흘러가는 텍스트 배너
세미 반응형이지만 PC만 지원하도록 만들었기 때문에, 최소너비를 1300픽셀로 잡아주었다.
이때, 컨텐츠의 수평 스크롤영역 때문에 가로스크롤이 생길 위험을 낮추기 위해 overflow-x:hidden
을 사용했는데, body와 wrapper에 둘다 각각 1300px의 min-width를 주고, wrapper에 overflow-x:hidden
을 사용해서 화면이 1300px보다 작아서 넘치는 영역에만 스크롤이 생길 수 있도록 코딩했다.
.wrapper{
min-width:1300px;
overflow-x: hidden;
}
body{
min-width:1300px;
}
각 섹션 내부 수평으로 스크롤되는 영역은 'group-hori', 수직으로 스크롤되는 영역은 'group-scroll'로 구성하여 컨트롤해서 구조파악하기 용이하게 했다.
<section class="sc-data sc-card">
<div class="group-hori">
.
.
</div>
<div class="group-scroll">
.
.
</div>
</section>
section들을 모은 영역은 독립적으로 존재할수 있는 article 태그로 감쌀 수 있다.
엔터프라이즈블록체인 사이트를 클론코딩하면서 DATA ID 내용이 나열되는 영역은 'DATA ID'라는 공통 내용을 담은 독립적인 컨텐츠기 때문에 article로 구성했다.
사이트의 모션 효과를 만들 위해 Greensock에서 만든 GSAP이라는 JS 라이브러리를 이용했다. 😎
GSAP의 플러그인인 ScrollTrigger를 함께 사용하여 스크롤을 이용해 애니메이션이 움직이고 멈추도록 만들었다.
기본적으로 나열된 순서에 따라 동작하지만, 동시에 동작하고 싶은 애니메이션은 addLabel을 이용해 Label을 선언하고, 중괄호 뒤에 붙여주면 같은 Label이 붙은 애니메이션은 동시에 동작하게 된다.
또 { 중괄호 안 } 의 duration, delay 속성을 활용하여 타이밍을 더 디테일하게 컨트롤할 수 있다.
const intro = gsap.timeline();
intro
.addLabel('a')
.to(".sc-intro .text-bg", {backgroundColor:"rgba(0,0,0,0.6)", duration: 100},'a')
.from(".sc-intro .t01", {autoAlpha: 0, duration: 100},'a')
.to(".sc-intro .t01", {autoAlpha: 0, duration: 100},"+=1")
.from(".sc-intro .t02", {autoAlpha: 0, duration: 100}, "+=1")
.to(".sc-intro .t02", {autoAlpha: 0, duration: 100},"+=1")
.from(".sc-intro .t03", {autoAlpha: 0, duration: 100}, "+=1")
.to(".sc-intro .t03", {autoAlpha: 0, duration: 100},"+=1")
.from(".sc-intro .t04", {autoAlpha: 0, duration: 100}, "+=1")
ScrollTrigger.create({
animation: intro,
trigger: ".sc-intro",
start: "top top",
end: "+=7000",
scrub: true,
pin: true,
})
animation
: 실행할 애니메이션의 이름
trigger
: 어떤 요소를 기준으로 할지
start
: 시작점 기준. "요소 / 창"
end
: 끝점 기준. "요소 / 창" , "+=숫자" ("+=3000"이면 시작점에서 3000px이 스크롤 될때까지 동작)
pin:true
: 애니메이션이 동작하는 동안에 영역이 화면에 고정
scrub:true
: 스크롤이 중단되거나 뒤로 돌아갈때 애니메이션도 함께 정지되거나 역재생한다.
① toggleClass
메서드를 이용해 간단하게 클래스를 on/off할 수도 있고,
② 'onEnter','onLeave', 'onEnterBack','onLeaveBack'
메서드를 이용하면 원하는 타이밍에 클래스를 on/off할 수도 있다.
// 1
ScrollTrigger.create({
animation: intro,
trigger: ".sc-intro",
start: "top top",
end: "+=7000",
scrub: true,
pin: true,
markers: false,
toggleClass:{
targets:"#topBtn", className:"hide"
}
})
// 2
ScrollTrigger.create({
trigger:'body',
start:"1000px 0%",
end:"100% 100%",
onEnter:function(){
$('.header').addClass('fixed')
},
onLeaveBack:function(){
$('.header').removeClass('fixed')
}
})
position:absolute
로 위치를 영역에 고정시키고, z-index
를 이용하여 뒤로 보냈다.
비디오에 autoplay
, loop
도 줬는데 ..! 자동재생이 될때가 있고 안될때가 있음 💧
왜 그런지 찾아보니까 크롬에서 소리가 있는 동영상은 자동재생이 안된다고, 이럴땐 muted를 써줘야한다고 한다.
<video src="./videourl" autoplay loop muted></video>
처음엔 각각 영역을 잡고 Background를 주었는데 이미지 영역과 텍스트 영역을 따로 잡고 코딩하는 방법이 더 간단하다.
이미지가 absolute로 붙어서 마지막 이미지부터 보일 것이기 때문에 역순으로 코딩한다.
<section class="sc-showcase">
<h2 class="blind">비주얼영역</h2>
<div class="group-visual">
<figure class="img-box"><img src="./asset/images/img-showcase03-pc.jpg" alt></figure>
<figure class="img-box"><img src="./asset/images/img-showcase02-pc.jpg" alt></figure>
<figure class="img-box"><img src="./asset/images/img-showcase01-pc.jpg" alt></figure>
</div>
<div class="group-text">
<div class="text-bg"></div>
<p class="t01">기록하고</p>
<p class="t02">증명하고</p>
<p class="t03">성장하기</p>
</div>
<div class="desc">
<div class="text-bg"></div>
<p>
엔터프라이즈블록체인은 블록체인 네트워크<br>
DATA ID를 활용해 그 문제를 해결하고 새로운 방식을<br>
제안하고자 합니다.
</p>
</div>
</section>
이미지 영역과 텍스트 영역은 absolute로 붙여주고, 각 영역의 너비와 높이를 잡아준다.
포인트는 다른 영역의 높이는 100vh로 잡고, 이미지를 담는 div영역만 100%로 잡기 !
그리고 overflow:hidden;
으로 height값이 잘리는 부분에서 넘치는 영역은 안보이게 한다.
.sc-showcase{
position: relative;
width: 100%; height: 100vh;
}
.sc-showcase .group-visual{
position: absolute;
top: 0; left: 0;
width: 100%; height: 100vh;
}
.sc-showcase .group-visual .img-box{
position: absolute;
top: 0; left: 0;
z-index: -2;
width: 100%; height: 100%;
overflow: hidden;
}
.sc-showcase .group-visual img{
width: 100%; height: 100vh;
object-fit:cover;
}
.sc-showcase .group-text{
position:absolute;
top: 0; left: 0;
width: 100%; height: 100vh;
.
.
}
.sc-showcase .desc{
position:absolute;
top: 0; left: 0;
width: 100%; height: 100vh;
.
.
}
이미지 넘어가는 타이밍이랑 텍스트 나타나고 사라지는 타이밍을 잘 배치해서 애니메이션을 만들어준다 .
이미지 넘어가는건 100%였던 height값을 0으로 바꿔서 구현함.
showcase
.addLabel('a')
.fromTo(".sc-showcase .group-text .text-bg", {backgroundColor:"rgba(0,0,0,0.0)"}, {backgroundColor:"rgba(0,0,0,0.6)",duration:20},"a")
.from(".sc-showcase .group-text", {autoAlpha:0,duration:20},"a")
.addLabel('b')
.to(".sc-showcase .group-text .text-bg", {backgroundColor:"rgba(0,0,0,0.0)",duration:20},"b")
.to(".sc-showcase .t01", {xPercent:100,duration:20},'b')
.to(".sc-showcase .t03", {xPercent:-100,duration:20},'b')
.addLabel('c')
.to(".sc-showcase .t01", {autoAlpha:0,duration:20},'c')
.to(".sc-showcase .t02", { autoAlpha:0,duration:20},'c')
.to(".sc-showcase .t03", {autoAlpha:0,duration:20},'c')
.to(".sc-showcase .img-box:nth-child(3)",{height:0,duration:20})
.to(".sc-showcase .img-box:nth-child(2)",{height:0,duration:20})
.to(".sc-showcase .desc .text-bg",{backgroundColor:"rgba(0,0,0,0.4)", duration:20},)
.from(".sc-showcase .desc",{autoAlpha:0,duration:20})
① .group-hori
영역이 수평으로 스크롤 됨, 마지막 카드는 고정
② .group-scroll
영역이 수직으로 스크롤 됨
③ ②번이 진행되면서 카드 리스트2 의 첫번째 카드가 페이드인되면서 ①에서 고정된 카드를 덮음 (안보이게)
④ 나머지 카드가 스크롤되어 올라오고, ③에서 나타난 카드 뒤로 겹쳐짐
시간을 가장 많이 잡아먹은 부분이었다.. 😇
모션자체는 구현할만 했는데 화면 너비나 높이가 줄어들면 자꾸 위치가 바뀌어서 힘들었음.
창 크기를 줄이거나 늘릴때도 가로 스크롤 컨텐츠의 끝점이 창 너비 끝점과 맞게 신경썼다.
컨텐츠 너비와 화면너비를 변수에 넣어서 연산해보거나 방법은 여러가지였지만 여러가지 시도를 해본끝에
가장 간단한 코드는 이거였다.
.to(".sc-economy .group-hori",{xPercent:-100,x:"100vw",duration:4},"a")
① xPercent:-100
: 컨텐츠의 너비만큼 왼쪽으로 밀어버린다
② x:"100vw"
: 왼쪽으로 밀었던걸 화면너비만큼 다시 오른쪽으로 땡겨온다
이걸 동시에 실행하면 손쉽게 맞출수있다
이렇게 쉬운걸 헤매다니 .. 😶🌫️
Top버튼이 position:fixed
로 항상 같은 영역에 붙어있다가 푸터까지 스크롤이 내려오면 fixed 속성이 사라진다. 이 부분은 ScrollTrigger와 클래스 컨트롤로 쉽게 구현할 수 있다.
#topBtn a{
position: fixed;
bottom: 40px; right: 100px;
.
.
}
#topBtn a.fixed{
position: absolute;
right: 100px; bottom:100px;
}
ScrollTrigger.create({
trigger: ".footer",
start: "0% 100%",
end: "110% 100%",
scrub: true,
onEnter:function(){
$('#topBtn a').addClass('fixed');
},
onLeaveBack:function(){
$('#topBtn a').removeClass('fixed');
}
});
한 방향으로 끝없이 흘러가는 배너는 keyframe을 활용해서 구현해주었다.
무한으로 텍스트가 나오는것처럼 보이지만 사실 트릭이다. 한 블럭 가면 다시 되돌아오는 구조로 만들면 됨.
<section class="sc-banner02">
<h2 class="blind">Join us</h2>
<div class="banner-overflow">
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
<span>JOIN <i>us</i></span>
</div>
</section>
.banner-overflow {
display: flex;
margin-left:-705px ;
}
.sc-banner02 span{
width: 235px;
height: 60px;
animation: banner02 8s linear infinite running;
padding: 0;
margin: 0;
}
@keyframes banner02 {
from { transform: translateX(0); }
to { transform: translateX(300%); }
}
공감하며 읽었습니다. 좋은 글 감사드립니다.