Hi, I’m Kang Byeong-hyeon.

..

[카카오 테크 캠퍼스 2기] 1단계 3주차 WIL - 스타벅스 예제 클론하기(3)




순차적 애니메이션 - 전역 버튼 스타일

Sementic Tag의 사용

Sementic Tag란?

sementic이란 의미론적, 의미론적인을 뜻한다.

즉, sementic tag란 의미를 부여하기 위한 역할의 태그라고 할 수 있다.

이전에 header 영역을 작업할 때에도 <div>태그가 아닌 <header>태그를 사용한 것 처럼, 의미가 없는 <div>대신 해당 영역이 하나의 문서(컨텐츠 그룹)라는 의미를 부여하기 위해 <section>이라는 태그를 사용하였다.

<body>
	<-- HEADER -->
	<hedaer>
		...
	</header>

	<-- VISUAL -->
	<section class="visual">
		...
	</section>
</body>

아래 MDN문서를 참고해보면 시멘틱 태그에는 <header><section> 말고도 다양한 의미를 부여할 수 있는 태그들이 존재한다는 것을 알 수 있다.

스크린샷 2024-04-23 오후 6.48.00.png

시맨틱-태그_html.webp

Semantics - MDN Web Docs 용어 사전: 웹 용어 정의

시맨틱 태그란? - 태그 요소의 종류와 이점

Sementic Tag를 사용하는 이유?

  1. 접근성 향상 스크린 리더 사용자에게 큰 이점을 줄 수 있다. 신체적, 인지적 장애가 있는 사람들을 포함하여 모든 사람에게 원활한 경험을 보장할 수 있다. 스크린샷 2024-04-23 오후 6.53.49.png

    Screen Reader

  2. SEO(검색엔진최적화) 향상 관련 키워드와 문구에 대해 웹페이지를 최적화하는 데 도움이 되고, 검색결과 상에서 웹 사이트 노출 순위를 높여 더 많은 트래픽을 유도할 수 있다.

버튼 공통 스타일로 정의하기

기본 상태 버튼 스타일 정의하기

/* COMMON */
.btn {
  display: block;
  width: 130px;
  padding: 10px;
  border: 2px solid #333;
  border-radius: 4px;
  color: #333;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  cursor: pointer;
  box-sizing: border-box;
  transition: 0.4s;
}

.btn:hover {
  background-color: #333;
  color: #fff;
}

기본 상태의 버튼을 디자인하고 버튼을 hover했을때 배경색와 글자색을 변경하도록 정의한다.

상태에 따른 버튼 스타일 정의하기

.btn.btn--reverse {
  background-color: #333;
  color: #fff;
}

.btn.btn--reverse:hover {
  background-color: transparent;
  color: #3333;
}

각 버튼 상태에 따른 디자인 정의를 일치 선택자를 통해 정의하고 hover했을 경우도 같이 디자인한다.

정의한 버튼의 클래스 적용하기

<a href="javascfipt:void(0)" class="btn btn--brown">자세히 보기</a>

일치 선택자로 정의하였기 때문에 기존 .btn클래스를 기본 디자인으로 .btn—brown와 같은 상태 클래스를 덮어씌우는 형태로 한칸 공백을 주고 클래스를 적용한다.

결과

스크린샷 2024-04-23 오후 7.31.10.png




순차적 애니메이션 - 순차적으로 요소 보이기

visual 내부에있는 모든 요소들을 순차적으로 페이드인 하여 보여주려고 한다.

우선 모든 요소들을 안보이게 opcity0으로 부여하고, 자바스크립트를 통해 순차적으로 보이게끔 opacity1로 설정하여 애니메이션을 부여할 예정이다.

.fade-in 클래스 정의 및 요소들 그룹핑

.visual .fade-in {
  opacity: 0;
}
<!-- VISUAL -->
<section class="visual">
  <div class="inner">
    <div class="title fade-in">
      <img
        src="./images/visual_title.png"
        alt="STARBUCKS DELIGHTFUL START TO THE YEARS"
      />
      <a href="javascfipt:void(0)" class="btn btn--brown">자세히 보기</a>
    </div>
    <div class="fade-in">
      <img
        src="./images/visual_cup1.png"
        alt="new OATMEAL LATTE"
        class="cup1 image"
      />
      <img
        src="./images/visual_cup1_text.png"
        alt="오트밀 라떼"
        class="cup1 text"
      />
    </div>
    <div class="fade-in">
      <img
        src="./images/visual_cup2.png"
        alt="new STARBUCKS CARMEL CRUMBLE MOCHA"
        class="cup2 image"
      />
      <img
        src="./images/visual_cup2_text.png"
        alt="스타벅스 카라멜 크럼블 모카"
        class="cup2 text"
      />
    </div>
    <div class="fade-in">
      <img src="./images/visual_spoon.png" alt="Spoon" class="spoon" />
    </div>
  </div>
</section>

순차적으로 요소 보이기

const fadeEls = document.querySelectorAll(".visual .fade-in");

fadeEls.forEach((fadeEl, index) => {
  gsap.to(fadeEl, 1, {
    delay: (index + 1) * 0.7,
    opacity: 1,
  });
});

결과

Apr-23-2024 19-33-59.gif




요소 슬라이드

Swiperjs란?

Swiper - The Most Modern Mobile Touch Slider

Swiperjs라이브러리는 요소들을 좌우 혹은 수직으로 슬라이드할 수 있게끔 도와주는 라이브러리이다.

해당 프로젝트는 swiper 6버전을 사용하며, 최신버전과의 차이는 다음과 같다.

<!-- Slider main container -->
<div class="swiper-container">
  <!-- Additional required wrapper -->
  <div class="swiper-wrapper">
    <!-- Slides -->
    <div class="swiper-slide">Slide 1</div>
    <div class="swiper-slide">Slide 2</div>
    <div class="swiper-slide">Slide 3</div>
  </div>
</div>
<!-- Slider main container -->
<div class="swiper">
  <!-- Additional required wrapper -->
  <div class="swiper-wrapper">
    <!-- Slides -->
    <div class="swiper-slide">Slide 1</div>
    <div class="swiper-slide">Slide 2</div>
    <div class="swiper-slide">Slide 3</div>
  </div>
</div>

6버전에서의 swiper 최상위 부모 클래스는 .swiper-container이고 최신 버전에서는 .swiper이다. 이 점을 고려해서 작성한다.

Swiperjs CDN 추가하기

Getting Started With Swiper

스크린샷 2024-04-24 오후 5.14.48.png

Swiperjs 라이브러리를 CDN을 통해 가져올 경우 위와 같이 가져올 수 있다.

현 프로젝트에서는 6.8.4 버전을 사용할 것이기 때문에 swiper@6.8.4를 기입하여 특정 버전의 라이브러리를 가져오도록 한다.

<link
  rel="stylesheet"
  href="https://unpkg.com/swiper@6.8.4/swiper-bundle.min.css"
/>
<script src="https://unpkg.com/swiper@6.8.4/swiper-bundle.min.js"></script>

공지사항 수직 슬라이드 적용하기

수직 슬라이드 데모 참고

스크린샷 2024-04-24 오후 5.10.52.png

수직 슬라이드의 데모를 확인하기 위해 데모에서 Vertical 탭을 클릭하면 관련 데모를 확인할 수 있다.

현 프로젝트는 바닐라 자바스크립트 환경이므로 데모 코드를 확인을 위해 core탭을 클릭하하면 코드를 확인해볼 수 있다.

스크린샷 2024-04-24 오후 5.11.43.png

스크린샷 2024-04-24 오후 5.11.56.png

Swpierjs를 사용하기 위한 HTML구조와 javascript코드를 간단하게 확인할 수 있다.

슬라이드 HTML 구조 작성

<div class="inner__left">
  <h2>공지사항</h2>
  <div class="swiper-container">
    <div class="swiper-wrapper">
      <div class="swiper-slide">
        <a href="javascript:void(0)"
          >크리스마스 & 연말연시 스타벅스 매장 영업시간 변경 안내</a
        >
      </div>
      <div class="swiper-slide">
        <a href="javascript:void(0)"
          >[당첨자 발표] 2021 스타벅스 플래너 영수증 이벤트</a
        >
      </div>
      <div class="swiper-slide">
        <a href="javascript:void(0)"
          >스타벅스커피 코리아 애플리케이션 버전 업데이트 추가 안내</a
        >
      </div>
      <div class="swiper-slide">[당첨자 발표] 뉴이어 전자영수증 이벤트</div>
    </div>
  </div>
  <a href="javascript:viod(0)" class="notice-line__more">
    <span class="material-symbols-outlined"> add_circle </span>
  </a>
</div>

수직 슬라이드 동작 구현

new Swiper(".notice-line .swiper-container", {
  direction: "vertical",
  autoplay: true,
  loop: true,
});

결과

Apr-24-2024 18-03-28.gif

프로모션 이미지 좌우 슬라이드 적용하기

슬라이드 요소 중앙 배치

.notice .promotion .swiper-container {
  width: calc(819px * 3 + 20px);
  height: 533px;
  position: absolute;
  top: 40px;
  left: 50%;
  /* margin-left: calc((819px * 3 + 20px) / -2); */
  transform: translateX(-50%);
}

좌우 슬라이드 동작 구현

new Swiper(".promotion .swiper-container", {
  direction: horizontal
  slidesPerView: 3,
  spaceBetween: 10,
  centeredSlides: true,
  loop: true,
  autoplay: {
    delay: 5000,
  },
});

투명도 설정으로 슬라이드 집중시키기

.notice .promotion .swiper-slide {
  opacity: 0.2;
}

.notice .promotion .swiper-slide-active {
  opacity: 1;
}

결과

Apr-24-2024 20-41-03.gif

페이지네이션 & arrow 버튼 추가 하기

페이지네이션 & arrow 버튼 HTML 구조

<div class="swiper-pagination"></div>
<div class="swiper-prev"></div>
<div class="swiper-next"></div>

페이지네이션 & arrow 버튼 요소 지정

new Swiper(".promotion .swiper-container", {
  slidesPerView: 3,
  spaceBetween: 10,
  centeredSlides: true,
  loop: true,
  // autoplay: {
  //   delay: 5000,
  // },
  pagination: {
    el: ".promotion .swiper-pagination",
    clickable: true,
  },
  navigation: {
    prevEl: ".promotion .swiper-prev",
    nextEl: ".promotion .swiper-next",
  },
});

결과

Apr-24-2024 21-58-33.gif

슬라이드 영역 토글 버튼 추가하기

토글 버튼을 클릭하면 프로모션 영역이 숨겨지거나 보여지도록 하는 역할을 구현한다.

토글 버튼 요소 추가 및 토글 구현하기

const promotionEl = document.querySelector(".promotion");
const promotionToggleBtn = document.querySelector(".toggle-promotion");
let isHidePromotion = false;

promotionToggleBtn.addEventListener("click", () => {
  isHidePromotion = !isHidePromotion;
  if (isHidePromotion) {
    promotionEl.classList.add("hide");
    return;
  }
  promotionEl.classList.remove("hide");
});

.hide 클래스 정의

.notice .promotion {
  position: relative;
  height: 693px;
  background-color: #f6f5ef;
  transition: height 0.4s;
  overflow: hidden;
}

.notice .promotion.hide {
  height: 0;
}

결과

Apr-24-2024 22-08-51.gif




유튜브 영상 배경

유튜브 영상은 보통 16:9 비율 화면의 크기로 제공되고 있다.

유튜브 영상을 배경으로 설정하려면 해당 비율에 대한 width값과 height값을 설정해야한다.

이는 부모요소와 자식요소의 관계를 통해 설정이 가능한데 해당 내용에 대한 예시는 다음과 같다.

<div class="container">
  <div class="item"></div>
</div>
.container {
  width: 500px;
  background-color: royalblue;
}

.container .item {
  width: 100%;
  height: 0;
  padding-top: 50%;
}

스크린샷 2024-04-25 오전 5.37.58.png

부모요소의 container에서의 width값과 자식요소 item의 padding-top을 각 2:1 비율로 설정한다고 가정할 때, 자식요소는 부모요소의 width500px을 기준으로 padding-top에 설정한 50%값인 250px를 갖게된다.

즉, 자식요소의 %크기는 부모요소의 크기를 기준으로 값이 설정되어진다는 것을 알 수 있고, 이를 활용하여 비율 설정이 가능하다.

유튜브 영상 배경 구조

<section class="youtube">
  <div class="youtube__area">
    <div id="player"></div>
  </div>
  <div class="youtube__cover"></div>
</section>

유튜브 영상 배경 스타일링

유튜브 영상이 보일 영역은 16:9 크기만큼 설정해놓고, 유튜브 영상을 중앙배치하여 영상의 중앙 부분만 보일수 있게 스타일링 한다.

.youtube {
  position: relative;
  height: 700px;
  background-color: #333;
  overflow: hidden;
}

.youtube .youtube__area {
  width: 1920px;
  background-color: orange;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.youtube .youtube__area::before {
  content: "";
  display: block;
  width: 100%;
  height: 0;
  padding-top: 56.25%;
}

.youtube .youtube__cover {
  background-image: url("../images/video_cover_pattern.png");
  background-color: rgba(0, 0, 0, 0.3);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

YouTube Player API

IFrame Player API를 사용하면 YouTube 동영을 가져오고 제어할 수 있다.

iframe 삽입에 대한 YouTube Player API 참조 문서

스크린샷 2024-04-28 오후 7.33.43.png

라이브러리에서 제공하는 예시코드를 살펴보면 onYouTubeIframeAPIReady() 메서드를 통해 YT객체에 있는 Player()메서드를 호출해서 제공하는 옵션들을 객체 형태로 전달하고 있는 것을 확인할 수 있다.

또한 HTML에서 정의한 playerid로 갖는 태그에 해당 영상을 삽입하는 기능을 수행한다는 것을 확인할 수 있다.

이전에 해당 요소를 마크업해놓았기 때문에 위 코드를 참고하여 다음과 같이 적용해보았다.

const tag = document.createElement("script");

tag.src = "https://www.youtube.com/iframe_api";

var firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

function onYouTubeIframeAPIReady() {
  new YT.Player("player", {
    videoId: "aCkI0tjzUbQ",
    playerVars: {
      autoplay: true,
      loop: true,
      playlist: "aCkI0tjzUbQ",
    },
    events: {
      onReady: (event) => {
        event.target.mute();
      },
    },
  });
}

결과

스크린샷 2024-04-28 오후 7.44.58.png

아이콘 반복 애니메이션 적용하기(feat. gsap)

유튜브 영상 배경화면 위에 아이콘 요소들을 통통튀는 효과의 애니메이션을 부여하려고 한다.

먼저 3개의 아이콘에 해당하는 요소들을 마크업한다.

각 아이콘 마크업 및 배치 시키기

<div class="inner">
  <img src="./images/floating1.png" alt="Icon" class="floating floating1" />
  <img src="./images/floating2.png" alt="Icon" class="floating floating2" />
  <img src="./images/floating3.png" alt="Icon" class="floating floating3" />
</div>
.youtube .floating1 {
  position: absolute;
  top: 50px;
  left: 0;
}

.youtube .floating2 {
  position: absolute;
  top: 350px;
  left: 150;
}

.youtube .floating3 {
  position: absolute;
  bottom: -200px;
  right: 0;
}

애니메이션 적용하기

각 요소에 애니메이션을 간단하게 적용하기 위해 gsap 라이브러리를 활용하여 구현한다.

function floatingObject(selector) {
  gsap.to(selector, 1, {
    y: 20,
    repeat: -1,
    yoyo: true,
  });
}

floatingObject(".floating");

Easing > GSAP > Docs & Learning

스크린샷 2024-04-28 오후 7.59.51.png

애니메이션의 변화를 주기 위해 gsap에서 제공하는 easing 페이지를 참고하였다.

해당 페이지를 참고하면 다양한 에니메이션을 그래프 형태로 preview를 확인할 수 있다.

추가로 type을 따로 설정하여 in, out을 설정할 수 있다.

원하는 core와 type을 선택하고 ease 속성에 대한 값을 복사한다. 본인은 power1를 in-out을 적용해보았다.

function floatingObject(selector) {
  gsap.to(selector, 1, {
    y: 20,
    repeat: -1,
    ease: "power2.inOut",
    yoyo: true,
    delay: 1,
  });
}

추가적으로 애니메이션과 각 요소의 동작 지연시간을 랜덤으로 부여하기 위해 다음과 같이 랜덤한 값을 반환하는 함수를 정의하였다.

function random(min, max) {
  return parseFloat((Math.random() * (max - min) + min).toFixed(2));
}
function floatingObject(selector, delay, size) {
  gsap.to(selector, random(1.5, 2.5), {
    y: size,
    repeat: -1,
    yoyo: true,
    ease: "power2.in",
    delay: random(0, delay),
  });
}

floatingObject(".floating1", 1, 15);
floatingObject(".floating2", 0.5, 15);
floatingObject(".floating3", 1.5, 20);

결과

Apr-28-2024 20-20-28.gif




소감

이번 주차는 Swiperjs, YouTube Player API 같은 오픈소스를 처음 접해보게 되었다.

Swiperjs 라이브러리를 이용하면, 요소들을 간편하게 수평이나 수직으로 슬라이드로 구현할 수 있다는 것을 알게 되었다.

또한 YouTube Player API를 활용하면 원하는 유튜브 영상의 ID만 있으면 쉽게 해당 영상을 가져올 수 있으며, 사용자에게 영상을 보여주기 전에 필요한 설정을 쉽게 할 수 있다는 것을 깨달았다.

마지막으로 GSAP의 easing을 활용하면 다양한 애니메이션과 타입을 사용하여 요소에 보다 디테일한 애니메이션을 적용할 수 있다는 것을 알게 되었다.