Starbucks
20210528 StarbucksClone03 : Notice 수직 슬라이드(Swiper.js), 반응형 요소 중간 배치, Promotion 수평 이미지 슬라이드(Pagination, Navigation Botton), 슬라이드 Toggle, Rewards 영역, 요소 비율 맞추기, 유튜브 영상 넣..
Starbucks Clone03
Notice (공지) : 수직 슬라이드
- 슬라이드가 되는 공지사항을 구현하는 것이다.
HTML
- 새로운 영역을 만드는 것이기 때문에 section 태그를 사용한다.
notice section
의 경우 좌우로 나뉘어서 영역을 차지하고 있고, 6:4 비율을 가지고 있다.- 배경 색깔만 지정하는
bg-left class
,bg-right class
요소가 있고 - 본격적인 내용은 앞에서 정의한 inner class 요소를 사용하여 중앙 정렬을 유지한다.
inner class
요소 안에서도 좌우를 나누어inner__left
와inner__right
가 존재함- inner__left 의 경우
공지사항
글자 부분swiper-container
라는 공지가 슬라이드 되는 부분notice-line__more
이라는 공지사항을 더보는 아이콘(material-icons add_circle
)이 들어있는 부분이 있다.
- inner__right 의 경우
스타벅스
글자 부분toggle-promotion
이라는 프로모션에 대한 정보를 띄우는 아이콘(material-icons upload
)이 들어 있는 부분이 있다.
- 배경 색깔만 지정하는
<section class="notice">
<div class="notice-line">
<div class="bg-left"></div>
<div class="bg-right"></div>
<div class="inner">
<div class="inner__left">
<h2>공지사항</h2>
<div class="swiper-container"></div>
<a href="javascript:void(0)" class="notice-line__more">
<div class="material-icons">add_circle</div>
</a>
</div>
<div class="inner__right">
<h2>스타벅스 프로모션</h2>
<div class="toggle-promotion">
<div class="material-icons">upload</div>
</div>
</div>
</div>
</div>
</section>
CSS
- 여기서 작업은 배경을 지정하거나, 주로 flex로 요소를 정렬 하거나, 요소 간의 비율을 맞추는 것
- 배경 같은 경우에는 요소를 차지하고 있어
absolute
값을 통해서 inner와의 연결을 끊어 독립적으로 처리하였다. (inner에 영향을 주지 않음) - 요소간의 비율을 맞출 때는 width 값에
%
단위를 사용해서 맞출 수 있다. - flex에서 사용되는
justify-content
,align-items
에대한 값으로center
,flex-start
,flex-end
가 있다는 것을 기억하자 (rigth, left가 아니다.)display: flex
의 특징으로 내부 요소에 width 값이 없으면 최소한으로 사용하므로 0이 될수도 있기에 width값을 잘 넣자!- 기초적인 container인 inner에서 height 값을 지정함으로써 높이를 유지하도록 한다. (주변 요소들 및 부모 요소의 크기도 inner에 의해서 같이 변하게 됨.)
- flex 사용시 여러 요소들이 존재할 때 어느 하나의 요소가 container의 나머지를 채울수 있게 하고 싶은 경우
flex-grow: 1
를 사용해서 나머지를 차지하게 할 수 있다. (여기에서는 swiper-container에 적용 되었다.)
/* 핵심 포인트만 CSS 코드 예시를 넣음 (notice css 전부가 아님 주의!) */
.notice .notice-line .inner .inner__left {
width: 60%;
height: 100%;
background-color: #333;
display: flex;
align-items: center;
}
.notice .notice-line .inner .inner__left .swiper-container {
background-color: orange;
height: 62px;
flex-grow: 1;
}
.notice .notice-line .inner .inner__left .notice-line__more {
width: 62px;
height: 62px;
display: flex;
justify-content: center;
align-items: center;
}
.notice .notice-line .inner .inner__right {
width: 40%;
height: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
}
Swiper.JS로 수직 슬라이드 구현하기
Swiper.js
- Swiperjs site
- Swiperjs : installation-cdn
- : cdn으로 제공하는 코드에는 원본이 있고
min
버전이 있는데, min 버전은 압축되어 조금더 최적화 되어 있어 min 버전을 활용하는 것을 추천 - JS 파일뿐만 아니라 CSS 파일에 대한 연결도 필요하므로 두개 모두 코드를 연결시켜 줄것!
- : cdn으로 제공하는 코드에는 원본이 있고
- Swiperjs : add swiper html layout
- Swiperjs : Vertical
- 원하는 Swiper을 선택하고, core를 누르면 어떻게 연결하고 사용하는지 알려줌.
Swiper HTML
- slide는 무조건 swiper-wrapper 로 묶어야 하는것 주의할 것!
- Pagination, Navigation button, Scrollbar 같은 경우는 swiper-container에 있어도 되고 없어도 됨, 하지만 슬라이드를 가릴 것을 우려한다면, 밖으로 빼는게 좋음
- 단, wrapper 부분에 들어가면 안됨
<!-- 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>
<!-- If we need pagination -->
<div class="swiper-pagination"></div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- If we need scrollbar -->
<div class="swiper-scrollbar"></div>
</div>
Swiper JS
new Swiper(선택자, 옵션)
- 옵션
- direction : 슬라이드할 방향
- autoplay : 자동 재생
- loop : 끝나면 처음 부터
// new Swiper(선택자, 옵션)
new Swiper(".notice-line .swiper-container", {
direction: "vertical",
autoplay: true,
loop: true,
});
Promotion : 요소 가운데 배치하기 (반응형, 요소 중간 지점 유지)
- 단순히 요소를 가운데 배치하는 것은 absolute, margin, flex의 방법으로 하면 쉽게 할 수 있다.
- 하지만, 해당 방법은 반응형 웹에서 사용할 때 절대적으로 요소의 중앙을 사용자의 화면에서 가운데를 유지하지는 못한다. (요소 자체 보다 창이 작아지는 경우)
- margin 방법으로 하게 되면 보통 창이 줄어들면 해당 여백까지만 좌우로 줄어 들어 중간을 유지하지만 요소 보다 창이 작아지게 되면 요소의 우측 부터 줄어 들게 된다.
- inner width 보다 큰 요소를 제어하는 경우
- 그래서 만약 요소 중간에 중요한 정보가 있어 창이 줄어 들어도 창이 요소의 중앙을 출력하고자 하면 이 방법을 사용 해야 한다.
HTML
<div class="promotion">
<div class="swiper-container">
<div class="swiper-wrapper">TEST!</div>
</div>
</div>
CSS
- 전체적인 컨셉은 inner 보다 큰 요소에서
absolute
의 기준점을 화면에 50% 부분으로 줌으로써 기본적으로 요소가 중앙에서 시작되게 한다. - 그리고 요소의 width 크기를 계산해서 요소의 width 의 절반 만큼 다시
margin
으로 재 위치 시킴으로써 중앙에 배치할 수있다. - 요소의 크기를 계산할 때 편하게 쓸수 있는
calc()
라는 함수가 있다.- calc 함수 사용의 예로 내부적으로 쓰이는 컨텐츠 크기와 margin을 합산하여 전체 width를 쉽게 계산 가능하다.
- 또한, 여기에서는 width의 절반을 계산할 때도 사용된다.
.notice .promotion {
height: 693px;
background-color: #f6f5ef;
position: relative;
}
.notice .promotion .swiper-container {
width: calc(819px * 3 + 20px);
height: 553px;
background-color: orange;
text-align: center;
font-size: 200px;
position: absolute;
top: 40px;
left: 50%;
margin-left: calc((819px * 3 + 20px) / -2);
Promotion : 수평 이미지 슬라이드 (Pagination, Botton)
- 위에서는 Promotion에 대한 전체적인 중앙 배치를 해보았고 이번에는, Promotion 부분에 수평 이미지 슬라이드 기능을 구현할 것이다.
- 해당 슬라이드는 Pagination 과 Naviagtion이 존재함
pagination
: 슬라이드들이 몇장인지, 어떤 슬라이드가 focus되어 있는지 그리고 특정 슬라이드로 이동할수 있는 UI 이다.navigation
: 다음 슬라이드로 이동하는 버튼
- 위의 슬라이더 기능은 위에서와 같이 Swiper.js를 사용함
HTML
- swiper-container
- swiper-wrapper
- slide * 5 (슬라이드 5개)
- img (해당 이미지)
- a 태그 버튼 (자세히 보기 버튼)
- slide * 5 (슬라이드 5개)
- swiper-wrapper
- swiper-pagination (특정 슬라이드 이동 UI)
- swiper-prev (이전 슬라이드 이동 버튼)
- icon : arrow_bakc
- swiper-next (다음 슬라이드 이동 버튼)
- icon : arrow_forward
- pagination, navigation(prev, next)
- wrapper 범위 침범 주의
<div class="promotion">
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<img
src="./images/promotion_slide1.jpg"
alt="2021 뉴이어, 스타벅스와 함께 즐겁고 활기차게 시작하세요!"
/>
<a href="javascript:void(0)" class="btn">자세히 보기</a>
</div>
<div class="swiper-slide">
<img
src="./images/promotion_slide2.jpg"
alt="기간 내 스타벅스 카드 e-Gift를 3만원 이상 선물 시, 아메리카노 e-쿠폰을 드립니다."
/>
<a href="javascript:void(0)" class="btn">자세히 보기</a>
</div>
<div class="swiper-slide">
<img
src="./images/promotion_slide3.jpg"
alt="뉴이어 푸드와 제조 음료를 세트로 구매 시, 뉴이어 음료 BOGO(1+1) 쿠폰을 드립니다."
/>
<a href="javascript:void(0)" class="btn">자세히 보기</a>
</div>
<div class="swiper-slide">
<img
src="./images/promotion_slide4.jpg"
alt="신년 MD 상품 포함 3만원 이상 구매 고객께 아메리카노(톨사이즈) 쿠폰을 드립니다."
/>
<a href="javascript:void(0)" class="btn">자세히 보기</a>
</div>
<div class="swiper-slide">
<img
src="./images/promotion_slide5.jpg"
alt="2017 DIGITAL LUCKY DRAW 100% 당첨의 행운을 드립니다!"
/>
<a href="javascript:void(0)" class="btn">자세히 보기</a>
</div>
</div>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-prev">
<div class="material-icons">arrow_back</div>
</div>
<div class="swiper-next">
<div class="material-icons">arrow_forward</div>
</div>
</div>
CSS
Slide CSS
- dev tool를 통해서 slide에 대한 class를 확인해 보면 active된 slide에는
swiper-slide-active
클래스가 들어 간다는 것을 알수 있다..swiper-slide
에 opacity를 줘서 기본적으로 조금 투명하게 만들고,swiper-slide-active
클래스에 opacity를 1로 줌으로서 현재 active가 된 slide를 뚜렷하게 하여 차이를 줌- 슬라이드 안에 들어갈 자세히 버튼의 경우
.btn
을 붙였기 때문에 width없이 absolute, margin으로 배치함
.notice .promotion .swiper-slide {
opacity: 0.3;
transition: opacity 1s;
position: relative;
}
.notice .promotion .swiper-slide-active {
opacity: 1;
}
.notice .promotion .swiper-slide .btn {
position: absolute;
/* width: 130px; .btn에 width가 있기 때문에*/
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
Pagination CSS
.swiper-pagination
의 경우 라이브러리에서 기본적으로position: absolute
,text-align: center
이 들어가 있음pagination
을 구성하는 요소인pagination-bullet
이diplay: inlin-block
으로 되어 있기 때문에pagination-align: center
로 pagination이 가운데 정렬이 가능하고 width 값도 추산이 되기 때문에 또 가운데 정렬이 가능함
- 이처럼 이런 것들을 알려면, 라이브러리에서 제공하는 공식문서만 보지 말고 dev tool로 직접 CSS를 확인해 가봐면서 분석해야함
- outline 속성은 focus 효과를 없애줌(swiper 라이브러리에서 acive에서 따로 focus를 지정하고 있기 때문에 없애도 됨)
- swiper-pagination-bullet 클래스를 통해서 bullet 커스텀이 가능함
- swiper-pagination-bullet-acitve로 active 상태인 경우도 커스텀이 가능함
/* 정렬 */
.notice .promotion .swiper-pagination {
bottom: 40px;
left: 0;
right: 0;
z-index: 0;
}
/* bullet 커스텀 */
.notice .promotion .swiper-pagination .swiper-pagination-bullet {
background-color: transparent;
background-image: url("../images/promotion_slide_pager.png");
width: 12px;
height: 12px;
margin-right: 6px;
outline: none;
}
.notice .promotion .swiper-pagination .swiper-pagination-bullet:last-child {
margin-right: 0;
}
.notice .promotion .swiper-pagination .swiper-pagination-bullet-active {
background-image: url("../images/promotion_slide_pager_on.png");
}
Navigation CSS
- Navigation의 경우, Navigation요소를 기본적으로 동그라미 모양으로 만듦
- 각 버튼 prev, next도 화면 가운데에 계속 유지하면서 배치하기 위해서
50%, margin
방법을 사용함
/* 여러개의 선택자 사용시 줄바꿈을 해주자 가독성을 위해 */
.notice .promotion .swiper-prev,
.notice .promotion .swiper-next {
width: 42px;
height: 42px;
border: 2px solid #333;
border-radius: 50%;
position: absolute;
top: 300px;
z-index: 1;
cursor: pointer;
outline: none;
display: flex;
justify-content: center;
align-items: center;
transition: 0.4s;
}
.notice .promotion .swiper-prev {
left: 50%;
margin-left: -480px;
}
.notice .promotion .swiper-next {
right: 50%;
margin-right: -480px;
}
.notice .promotion .swiper-prev:hover,
.notice .promotion .swiper-next:hover {
color: #fff;
background-color: #333;
}
슬라이드 영역 토글
- 앞서 notice 부분에 있던 promotion toggle키를 활성화 시켜 promotion 슬라이드를 접었다 폈다하고자 함
- 해당 기능을 구현하기 위해서는 JS을 통해서 구현할 수 있다.
JS
- 일단
promotion
과toggle-promotio
n을 제어하기 위해서 document를 통해서 요소를 가져온다. - 숨기거나 안숨기는 상태를 표시하기 위해서
isHidePromotion
변수를let
으로 만들어true
,false
를 왔다 갔다 할수 있게 한다. - 그리고
toggle-promotion
에 eventListener를 달아서 클릭시 callback 함수를 실행시키킨다.- callback함수는
isHidePromotion
의 상태를!
부정연산자를 통해 반대로 변경하여 재할당 해준다. - 그리고 if문으로
isHidePromotion
의 상태에 따라.hide
클래스를 classList에 넣거나 제거하도록 코드를 짠다.
- callback함수는
const promotionEl = document.querySelector(".promotion");
const promotionToggleBtn = document.querySelector(".toggle-promotion");
let isHidePromotion = false;
promotionToggleBtn.addEventListener("click", function () {
isHidePromotion = !isHidePromotion;
if (isHidePromotion) {
promotionEl.classList.add("hide");
} else {
promotionEl.classList.remove("hide");
}
});
CSS
- JS를 통해서 hide라는 클래스를 제어하는 데 hide가 해당 요소를 안보이게 CSS 속성을 지정해야 한다.
- 요소를 안보이게 하는 방법은 두가지가 있다.
display: none;
hieght: 0;
- 단,
display: none
의 경우 transition 속성을 지정해도 반응하지 않기 때문에 자연스러운 애니메이션을 넣고자 한다면hieght: 0
으로 넣어야 한다. - hieght 같은 경우 줄인다고 해서 안에 있는 요소가 넘쳐 보일 수도 있기 때문에
overflow: hidden
으로 완전히 안보이게 해야한다.
- 단,
.notice .promotion {
height: 693px;
background-color: #f6f5ef;
position: relative;
transition: height 0.4s;
overflow: hidden;
}
.notice .promotion.hide {
/* display: none; transition을 줄수 없어서 사용하지 않음*/
height: 0;
}
Rewards 영역 구현하기
- 시각적으로 배경을 block으로 사용하고 내용은 inner에 들어가고, 해당 inner에 버튼들이 있는 형태
- inner에 들어가는 사진이 좌우의 색깔이 달라서 좌우여백을 해당 색깔을 이어 나가고자 함
- 그래서 notice에서 썻던 방법인 bg-left, bg-right 요소를 넣고 absolute로 독립적으로 배경으로 활용하여 inner의 배경을 이어준다.
- 그리고 오르쪽에 위치한 버튼들은 btn-group으로 묶어 배치한다.
- 회원 가입 버튼의 경우, 차이점을 두어 btn--reverse class를 사용했다.
HTML
<section class="rewards">
<div class="bg-left"></div>
<div class="bg-right"></div>
<div class="inner">
<div class="btn-group">
<div class="btn btn--reverse sign-up">회원가입</div>
<div class="btn sign-in">로그인</div>
<div class="btn gift">e-Gift 선물하기</div>
</div>
</div>
</section>
CSS
- 해당 CSS 처리과정에서 기억해야 할 것은
btn-group
에서flex-wrap: wrap
을 사용해서 버튼들의 나열에서 줄을 만들게 했고btn-gift
에서flex-grow: 1
을 통해서 줄에 남은 여백을 모조리 채울수 있게 했다는 것
/* REWARDS */
.rewards .btn-group {
position: absolute;
bottom: 24px;
right: 0;
width: 250px;
display: flex;
flex-wrap: wrap;
}
.rewards .btn-group .btn.gift {
margin-top: 10px;
flex-grow: 1;
}
요소 비율 맞추기
- padding 은 % 단위 사용시 부모의 width를 기준으로 한다.
- (부모가 height가 존재해도 width 값을 기준으로 함)
- 그렇게 하여 padding 값때문에 부모 요소는 높이를 가지게 되어 화면에 표시가 된다.
- 즉, 자식 padding 에
%
를 넣어 부모는width값
을 입력하면 그 비율에 맞게 height 값이 계산되어 표현이 됨 - 이를 활용해서
56.25%
값을 넣으면 일반적인 영상 비율인 9:16 비율을 유지하는 요소를 만들 수 있다.
See the Pen vYxegLe by RaccoonCode96 (@raccooncode96) on CodePen.
유튜브 영상 넣기 (Youtube Iframe API)
JS
- var 변수 키워드는 현재 쓰는 cont 및 let을 사용해도 상관 없다.
- script 태그의 요소를 바디에 생성해서 tag변수에 할당하고
- tag에 src 속성에 youtube API를 넣어 연결함
- 바디에 있는 script 태그중 첫번째 것을 가져와서 firstScriptTag에 할당함
- firstScriptTag 요소의 부모 요소(parentNode)의 내부에서 tag요소를 firstScriptTag 앞에 삽입함
부모노드.insertBefore(삽입할 노드, 부모 내부의 기준점 노드)
- 부모노드의 내부에서 기준점 노드의 앞에 삽입할 노드를 삽입함
- javascript가 모두 읽히면
onYouTubeIframeAPIReady()
함수가 실행되는데- onYouTubeIframeAPIReady 함수
- YT클래스의 Player 함수를 통해서 해당 영상을 실행함
Player('player를 넣을 요소의 id', {옵션})
- YT클래스의 Player 함수를 통해서 해당 영상을 실행함
- onYouTubeIframeAPIReady 함수
// This code loads the IFrame Player API code asynchronously.
var tag = document.createElement("script");
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
function onYouTubeIframeAPIReady() {
// 이름 변경 하면 안됨
new YT.Player("player", {
videoId: "An6LvWQuj_8", // 최초 재생할 유튜브 영상 ID
playerVars: {
autoplay: true, // 자동 재생 유무
loop: true, // 반복 재생 유무
playlist: "An6LvWQuj_8", // 반복 재생할 유튜브 영상 ID 목록
},
events: {
// ready되었을 때 실행되기 전 할 것
onReady: function (event) {
event.target.mute(); // mute 지정
},
},
});
}
HTML
youtube section
는 페이지에서 영상이 위치하는 것과, 영상에서 얼만큼 보이게 할것인지 정하는 영역youtube__area
는 실제 youtube(id player 부분) 영상이 들어 있는 부분이다.- 영상의 크기 제어
- 영상의 비율 제어
- 영상의 어떤 일부분이 youtube section에 보이게 제어
youtube__cover
는 영상위에 filter를 씌우기 위함임
<!-- YOUTUBE VIDEO-->
<section class="youtube">
<div class="youtube__area">
<div id="player"></div>
</div>
<div class="youtube__cover"></div>
</section>
CSS
.youtube
의 경우 영상이 실제로 사이트에서 보일 영역의 사이즈 height를 700px, 그리고overflow: hidden
을 통해서 영상이 넘치는 부분을 안보이게함 (영상의 일부분만 디자인적으로 사용하고자 하기 때문에 이렇게 사용함)
/* YOUTUBE VIDEO */
.youtube {
position: relative;
height: 700px;
background-color: #333;
overflow: hidden;
}
.youtube__area
의 경우 영상의 크기를 지정하기 위해서width:1920px
로 지정하였다.- 그리고 해당 영상이 화면 중앙에 계속 위치하게 시키기 위해서
absolute, 50%, margin
방법을 사용하였으며 여기에서는, 상하좌우 모두 중앙에 위치시키기 위해서 top, left 둘다 썻다.
.youtube .youtube__area {
width: 1920px;
position: absolute;
left: 50%;
margin-left: calc(1920px / -2);
top: 50%;
margin-top: calc(1920px * 9 / 16 / -2);
}
- 사실 영상의 비율을 제어하려면 자식요소가 필요한데, html적으로 자식을 생성하는 것보다 css적으로 해결하는 방법을 사용하는 것이 좋다.
- 그래서
가상요소
를 사용하여 내부의 가상 요소를 만들고, 가상요소의 경우 inline 이기 때문에 block요소로 지정해주고,width: 100%
,height:0
처리하고padding-top:56.25%
를 통해 16:9 비율로 영상이 갖추어 지게 하였다.
.youtube .youtube__area::before {
content: "";
display: block;
width: 100%;
height: 0;
padding-top: 56.25%;
}
youtube__cover
는 필터의 역할을 하기 때문에rgba(0, 0, 0, 0.3)
을 통해서 투명검정의 해당 이미지 패턴을 씌운다.
.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%;
}
#player {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}