📌
사이트 명: 품고 반응형 (Poomgo)
제작 기간: 22.08.27 ~ 22.08.31 (5일 소요)
사용 언어: html, css, jQuery, java script, GSAP
[Poomgo 반응형 웹 클론 코딩 작업]
GSAP 플러그인을 활용하여 다양한 스크롤 애니메이션 기능들을 구현하는 법을 배운 반응형 클론 코딩 작업물입니다!
💡Learning point
- css 미디어 쿼리
- header, gnb 영역
- picture>source 태그 활용
- rolling banner 영역
- tab 영역 스크립트
- GSAP 라이브러리 활용
@media (조건) {
스타일
}
@media all and (max-width: 1300px){
.sc-main .text-wrap{
max-width: 704px;
top:calc(30vh - 124px);
padding-top: 58px;
}
... 이하 생략
}
@media all and (max-width: 750px){
.header{
min-height: 64px;
height: 64px;
}
... 이하 생략
}
@media (min-width:600px) and (max-width:820px){
.sc-main .banner-area{
padding-left: 50px;
}
}
@media all and (max-width:600px){
.banner-area .swiper-slide img{
width: 20px;
height: 20px;
}
}
해당 사이트의 break point를 참고하여 제작했다.
공통적으로는 750과 1300이라는 두 개의 break point를 만들고 특정 사이즈에서 따로 수정되어야 하는 부분들은 각각 잡아서 수정해주었다.
스크롤을 내리면 header 및 gnb 영역의 디자인이 바뀌도록 설정
[css]
/* 스크롤 내린 후 header */
.header.fixed{
background: #fff;
}
.header.fixed h1{
position: relative;
width: 160px;
height: 32px;
background: url(../images/logo-blue.svg);
background-repeat: no-repeat;
background-size: 160px 32px;
}
.header.fixed .gnb-item:not(:last-child){
color: #4d5968;
}
.header.fixed .group-header .depth1{
background: #fff;
color: #4d5968;
}
.header.fixed .group-header .gnb-item .depth1::after{
content: '';
background: #0040d1;
}
.header.fixed .group-header .depth1 > li:hover a{
color: #4d5968;
background: #f4f8ff;
}
[js]
//header 스크롤 이벤트
$(window).scroll(function(){
const curr = $(this).scrollTop();
if (curr > 0) {
$('.header').addClass('fixed');
} else {
$('.header').removeClass('fixed');
}
})
$(window).trigger('scroll');//스크롤 이벤트 강제 실행
<picture class="bg">
<source srcset="./assets/images/slide01.webp" media="all and (min-width: 750px)">
/* 750px 사이즈 이후부터는 pc용 이미지 */
<img src="./assets/images/slide01-mo.webp" alt="슬라이드 이미지01">
/* 750px 사이즈까지는 모바일용 이미지 */
</picture>
@keyframes
를 활용한 애니메이션을 적용했다.[html]
<div class="logo-slide" data-fade>
<div class="img-box row1">
<img src="./assets/images/partner01.webp" alt="파트너사 브랜드 로고">
<img src="./assets/images/partner01.webp" alt="파트너사 브랜드 로고">
</div>
<div class="img-box row2">
<img src="./assets/images/partner02.webp" alt="파트너사 브랜드 로고">
<img src="./assets/images/partner02.webp" alt="파트너사 브랜드 로고">
</div>
</div>
transform: translateX(-100%);
로 미리 x축을 당겨 시작점을 같게 만들어준 뒤 애니메이션을 적용시킨다.[css]
.sc-partnership .img-box{
display: flex;
position: absolute;
width: 2329px;
height: 232px;
}
.sc-partnership .img-box.row1{
top: 0; left: 0;
animation: movetoleft 50s linear infinite;
}
@keyframes movetoleft{
0%{
transform: translateX(0);
}
100%{
transform: translateX(-100%);
}
}
.sc-partnership .img-box.row2{
bottom: 0; right: 0;
animation: movetoright 50s linear infinite;
transform: translateX(-100%);
}
@keyframes movetoright{
0%{
transform: translateX(-100%);
}
100%{
transform: translateX(0);
}
}
/* 탭 영역*/
<div class="tab-nav">
<ul class="skill-list" role="tablist">
<li class="skill-item active" role="presentation">
/* 탭 영역 active시 보이는 영역*/
<span class="move"></span>
<a href="#skill01" data-target="#skill01" role="tab">업무 자동화</a>
</li>
<li class="skill-item" role="presentation">
<a href="#skill02" data-target="#skill02" role="tab">빅데이터 분석</a>
</li>
<li class="skill-item" role="presentation">
<a href="#skill03" data-target="#skill03" role="tab">수요 예측</a>
</li>
</ul>
</div>
/* 탭 컨텐츠 영역 */
<div class="tab-contents">
<div id="skill01" class="cont active">
... 이하 생략
</div>
<div id="skill02" class="cont">
... 이하 생략
</div>
<div id="skill03" class="cont">
... 이하 생략
</div>
</div>
[js]
//탭영역 nav focus 구현
$(".skill-item").click(function (e) {
e.preventDefault();
//탭 부분이 클릭되면
i = $(this).index();//순서 구하기
w = $(".move").width();//너비 구하기
$(".move").css("left", w * i);//순서*너비 값만큼 left값 주기
if ($(".move").width() >= 0) {
$(this).addClass("active").siblings().removeClass("active");
//move에 값이 생기면 해당 탭 영역 활성화 시키고, 나머지 비활성화
}
});
//해당하는 탭 컨텐츠 노출
const tabList = document.querySelectorAll(".tab-nav .skill-item");
const contents = document.querySelectorAll(".tab-contents .cont");
let activeCont = ""; //현재 활성화 된 컨텐츠
for (var l = 0; l < tabList.length; l++) {
tabList[l]
.querySelector(".skill-item a")
.addEventListener("click", function (e) {
e.preventDefault();
for (var j = 0; j < tabList.length; j++) {
//나머지 버튼 클래스 제거
tabList[j].classList.remove("active");
//나머지 컨텐츠 display:none 처리
contents[j].style.display = "none";
}
//버튼 관련 이벤트
// this.parentNode.classList.add('active');
//버튼 클릭시 컨텐츠 전환
activeCont = this.getAttribute("href");
document.querySelector(activeCont).style.display = "block";
});
}
스크롤에 반응하는 애니메이션을 구현하기 위해 GSAP scrollTrigger 라이브러리를 활용했다. GSAP를 활용하기 위해서는 gsap cdn과 사용할 라이브러리 cdn을 세팅해두어야 한다.
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/ScrollTrigger.min.js"></script>
scrollTrigger
scrollTrigger:{ trigger:"기준 요소", start:"top top", //[기준 요소 시작점, 윈도우 시작점] top->0% bottom->100% 20%,30% 다됨 end:"bottom top"//기준 markers:true, //페이지 내에 시작점, 끝점 표시 scrub:1 // 반복하거나, 시작점부터 끝점까지 동작 이어지도록(end 필수) }
break point를 지정하여 해당 지점에서 원하는 동작을 실행하도록 설정
ScrollTrigger.matchMedia({ "(min-width: 1025px)": function() {}, "(min-width: 768px) and (max-width: 1024px)": function() {}, "(max-width: 767px)": function() {}, "all": function() {} });
헤더 영역에 가려지지 않게 헤더 높이만큼을 슬라이드 영역 높이에서 빼주고, 화면이 고정된 상태에서 가로로 슬라이드 가 동작하도록 구현했다.
[css]
.sc-experience .group-list{
width: 400vw;
display: flex;
height: calc(100vh - 100px);
//헤더 높이 100px을 빼줌
}
.sc-experience .content{
width: 100vw;
//한 슬라이드가 화면에 가득 차도록
padding: 5px 15px 40px;
}
[js]
//gsap 슬라이드 영역
ScrollTrigger.matchMedia({
//large
"(min-width:751px)": function () {
//751px 이상부터 동작하도록
gsap.to(".sc-experience .group-list", {
scrollTrigger: {
trigger: ".group-list", //기준
start: "top 100px", //기준 시작점, 윈도우 시작점 => 헤더 영역 제외
end: "+=500%", //기준 끝점, 윈도우 끝점 => 트리거의 5배의 스크롤 값
// markers: true,
scrub: 1,
pin: true
//슬라이드 되는 동안 화면이 고정되도록
},
xPercent: -75
});
}
});
스크롤을 내리면 배너가 가로로 점점 길어지는 애니메이션 구현.
좌우로 하얀색 사각형을 만들어주고, 스크롤 시 이 길이가 조절되도록 설정했다.
[html]
<div class="banner-area panel-banner">
<div class="img-box"><img src="./assets/images/banner.webp" alt="배너 이미지"></div>
<p class="txt-box"><span>비즈니스 성장에 필요한<br>품고의 서비스를 확인하세요</span></p>
<span class="panel left-panel"></span>
<span class="panel right-panel"></span>
</div>
[css]
.left-panel{
position: absolute;
top: 0;left: 0;
width: 400px;
height: 100%;
background: #fff;
}
.right-panel{
position: absolute;
top: 0;right: 0;
width: 400px;
height: 100%;
background: #fff;
}
[js]
//배너 패널 영역
gsap.to(".panel", {
scrollTrigger: {
trigger: ".panel-banner",
start: "top 100%",
end: "bottom 50%",
scrub: 1
//스크롤 시, 반복되도록
},
width: 0
//width가 0이 될 때까지 동작
});
페이지 내에 스크롤 시 페이드업 되는 기능을 가진 섹션이 많아서,
동일한 data명을 주고 그 값을 활용해서 스크롤 트리거 기능을 적용했다.
[html]
<div class="text-wrap" data-fade>
<h2 class="headline">운영 솔루션</h2>
<strong class="main-txt">남다른 디테일로<br>완-벽한 물류 환경</strong>
<p class="sub">어떤 점이 궁금하세요?</p>
</div>
[js]
페이드업 영역
- data-fade값을 가진 요소들은 단순 페이드업 되도록 적용
$("[data-fade").each(function (i, l) { gsap.from(l, { scrollTrigger: { trigger: l, start: "top 100%", end: "bottom 100%" // markers:true, // scrub:1 }, opacity: 0, yPercent: 20 }); });
- data-child값을 가진 요소의 자식 요소들은 순차적으로 페이드업
$("[data-child]").each(function (i, l) { child = $(this).find("> *"); gsap.from(child, { scrollTrigger: { trigger: l, //[기준] start: "top 90%", //[기준시작점][윈도우시작점] 0% -> top or 100% -> bottom end: "bottom 90%" //[기준끝점][윈도우끝점] // markers:true, // scrub:1 }, opacity: 0, yPercent: 20, stagger: 0.1 //stagger값을 주면 요소들이 순차적으로 움직인다 }); });
scrollTrigger의 활용 방법은 무궁무진한 것 같은데 아직 헷갈리는 게 많아서 더 자주 사용해봐야 익숙해질 것 같다..! 그래도 새로운 기능 너무 신기하고 재밌어