웹페이지가 SNS(인스타, 카톡 등)로 공유될 때 우선적으로 활용되는 정보
작성법 : meta property = "og:~~" content="~~"
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Starbucks" />
<meta property="og:title" content="Starbucks Coffee Korea" />
<meta property="og:description" content="스타벅스는 세계에서 가장 큰 다국적 커피 전문점입니다." />
<meta property="og:image" content="./images/starbucks_seo.jpg" />
<meta property="og:url" content="https://starbucks.co.kr" />
og:type
: 페이지의 유형(E.g, website, video.movie)
og:site_name
: 속한 사이트의 이름
og:title
: 사이트 자체가 아닌 페이지의 이름(제목)
og:description
: 페이지의 간단한 설명, sns에서 악성 페이지로 감지할 수 있기 때문에 최대한 간단하게 작성
og:image
: 페이지의 대표 이미지 주소(URL)
og:url
: 페이지 주소(URL)
오픈그래프랑 비슷한테 트위터에 활용
작성법 : meta property = "twitter:~~" content="~~"
<meta property="twitter:card" content="summary" />
<meta property="twitter:site" content="Starbucks" />
<meta property="twitter:title" content="Starbucks Coffee Korea" />
<meta property="twitter:description" content="스타벅스는 세계에서 가장 큰 다국적 커피 전문점입니다." />
<meta property="twitter:image" content="./images/starbucks_seo.jpg" />
<meta property="twitter:url" content="https://starbucks.co.kr" />
twitter:card
: 페이지(카드)의 유형(E.g. summary, player)
twitter:site
: 속한 사이트의 이름
twitter:title
: 사이트 자체가 아닌 페이지의 이름(제목)
twitter:description
: 페이지의 간단한 설명, sns에서 악성 페이지로 감지할 수 있기 때문에 최대한 간단하게 작성
twitter:image
: 페이지의 대표 이미지 주소(URL)
twitter:url
: 페이지 주소(URL)
※ 보통 외부에서 검색, 접속해 빨리 파악해야하는 특징이 있기에 되도록 head
태그 안 다른 meta
, title
다음 최상단에 코드를 작성하기
기본 : link
태그를 CSS 파일 앞에 두고 CSS 속성을 CSS 파일에 적용해 사용하는 방법
- google fonts 사이트 접속해서 검색, nanum
- 고르고 원하는 굵기를 + 눌러서 추가한 다음 use on the web에서 고르기
link
태그와import
방식을 골라 코드를 작성
3-1. CSS 파일에font-family
를 적용해야 하기에link
태그일 시 css 파일보다 먼저 작성하기- use on~ 그 아래에 CSS Rules에 전용 폰트 속성이 있으니 복사 후 바디태그 안에 작성, 그 하위 요소들 모두 적용
- 기본 서체 설정 끝!
※ 폰트 라이센스들을 잘 구별해서 활용하기
color: #333;
: 기본 폰트 색상은 완전 검은색인데 디자인적으로 촌스러워서 body
선택자 안 글꼴 위에 color: #333;
작성하면 좀 더 보기좋음line-height
: 행간 높이를 1.4로 잡아 보기에 불편함 없이 설정font-size: 16px;
, font-family: 400;
: body
선택자에 명시해줘 상속을 보다 명확하게 받아줌body { /* 폰트 기본 설정 */
color: #333;
font-size: 16px;
font-weight: 400;
line-height: 1.4;
font-family: 'Nanum Gothic', sans-serif;
}
해당하는 리소스 이미지를 현업할 때는 디자인 팀이 없거나 있다고 해도 하나 하나 제때 제때 요구할 수 없기 때문에 기본적인 이미지(검색:돋보기, 슬라이드, 상단 이동 등)을 찾을 수 있는 사이트를 매사에 알면 좋다.
※ 강의와 차이점이 있음...
벡터 기반 구글의 기본 아이콘을 사용할 수 있다! Google fonts 사이트! div
태그여도 성질만 달라질뿐 쓸 수 있다!
- Google fonts 사이트에 들어가 icons 탭에 들어가기
- 검색창에 material icons로 검색 카테고리 바꾸고 원하는 걸 검색
- icon font link 태그를 복사 위해 instructions 들어가서 복사
head
태그 아래, CSS 파일 위로link
태그 붙여넣기(폰트사이즈와 동일)- 원하는 아이콘 선택 후 해당
span
태그 복사 후 html에 붙여넣으면 끝- 일반적인 font가 아니기에 직접
style
태그를 달아 수정함
다른 무료 아이콘 사이트들도 많다! 핵심은 알아서 잘 찾아 적용해야한다는 것이다.
헤더 태그를 이용한 로고, 메인 메뉴, 서브 메뉴 등 맨 위에 기본적인 구조 및 CSS 작성
Block Element Modifier : HTML의 클래스 속성의 작명법! 변수명을 정할 때 스트레스를 덜어주고 직관적이어서 수정할 때 용이
요소__일부분 : 요소의 일부분 표시 - 언더스코어 2개
요소--상태 : 요소의 상태를 표시 - 대시 2개
<!-- 그냥 네이밍: 간단함, 누가 누구껀지 알아보기 힘듬 -->
<div class="container">
<div class="name"></div>
<div class="item">
<div class="name"></div>
</div>
</div>
<!-- BEM을 활용해 네이밍: 번거로움, 직관적 -->
<div class="container">
<div class="container__name"></div>
<div class="item">
<div class="item__name"></div>
</div>
</div>
<!-- 버튼의 일반, 완료됨, 오류 상태: 두 단어가 별개로 보임 -->
<div class="btn primary"></div>
<div class="btn success"></div>
<div class="btn error"></div>
<!-- BEM의 네이밍으로 하면 btn의 상태를 직관적으로 보여줌 -->
<div class="btn btn--primary"></div>
<div class="btn btn--success"></div>
<div class="btn btn--error"></div>
header
태그 사용, div
와 비슷하게 기능적 역할은 없지만 header라는 의미를 사람에게 줘서 구별하게 만들어줌, 클래스처럼 쓰임
<!-- HEADER -->
<header>
<div class="inner">
<a href="/" class="logo">
<img src="./images/starbucks_logo.png" alt="STARBUCKS">
</a>
</div>
</header>
a href="/"
: 도메인, 즉 index.html이 생략, 절대경로이기 때문에 / 하나로 index.html로 이동하겠다 라는 의미
/* COMMON */
img { /* 이미지 블럭화 : baseline */
display: block;
}
/* HEADER */
header {
background-color: #f6f5f0;
border-bottom : 1px soild #c8c8c8;
}
header .inner {
width: 1100px;
height: 120px;
margin: 0 auto; /* 로고 좌우 여백 중간 설정 */
position: relative; /* 내 자신에 position을 따름*/
}
header .logo {
height: 75px;
position: absolute; /* 부모요소에 따름 */
top: 0;
bottom: 0;
left: 0;
margin: auto; /* 로고 좌우 여백 중간 설정 */
}
※ position: relative;
설정하기 전 부모를 잘 보기
margin: auto;
는 컴퓨터가 계산해 설정하는 외부여백들을 '같은 비율'로 맞춘다. ★margin
에 0 생략 가능
position
으로 어디에 배치할지 기준 정함top
,bottom
,left
,right
의 기준 잡을 상하좌우에 속성값을 지정해 브라우저가 계산하게끔 재료를 줌height
,width
를 명확히 작성해 가운데 배치하는 요소에 정확한 너비, 폭을 줘서 가운데에 배치를 할 수 있다.
걍 가운데 배치 하려는 거에 기준과 맞는 값을 줘 계산하게 만들자
정렬도 있고 다른 배치 방식도 있지만 이런 방식도 있다.
상하좌우, 상하만, 좌우만 다 다르게 설정
header .logo { /* 상하좌우 가운데 정렬 */
width: 75px
height: 75px;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
}
영어 소문자를 쓸 때 꼬리 부분을 쓰려고 남겨두고 기준선을 만든게 baseline임. inline
특성, 글자처럼 취급되는 요소(특히 img
)를 다룰 때 베이스라인을 기준으로 아래쪽에 약간의 공간이 있는 현상이 생김! 이해하고 맞는 방법으로 수정하자
수정법 : img {display: block;}
로 해서 레이아웃처럼 블럭 취급해버리면 간단
로고 옆 sign in, my starbucks 등과 검색 옵션을 넣음
.inner
안 a
태그 이후 작성(a
태그와 형제)
<div class="sub-menu">
<ul class="menu">
<li>
<a href="javascript:void(0)">Sign In</a>
</li>
<li>
<a href="javascript:void(0)">My Starbucks</a>
</li>
<li>
<a href="javascript:void(0)">Customer Service & Ideas</a>
</li>
<li>
<a href="javascript:void(0)">Find a Store</a>
</li>
</ul>
<div class="search">
<input type="text" />
<div class="material-icons">search</div> <!--구글 아이콘-->
</div>
</div>
li
와 검색 아이콘, 텍스트박스input
입력a
링크의 사이트가 정해지지 않았다면 임시로 <a href="javascript:void(0)"></a>
로도 입력해서 나중에 js로 제어 가능header .sub-menu {}
header .sub-menu ul.menu { /* ul.menu는 정말 흔함, 앞 부모요소 작성 必 */
font-family: Arial, sans-serif;
display: flex;
}
header .sub-menu ul.menu li {
position: relative;
}
header .sub-menu ul.menu li::before { /* 가상요소선택자 복습 */
content: ""; /* 인라인 요소 */
display: block; /* 명시해도 되고 안해도 되고 */
width: 1px;
height: 12px;
background-color: #e5e5e5;
position: absolute; /* 이 속성으로 블럭 요소로 바뀌었음 */
top: 0;
bottom: 0;
margin: auto 0;
}
header .sub-menu ul.menu li:first-child::before {
display: none;
}
header .sub-menu ul.menu li a { /* UX */
font-size: 12px;
padding: 11px 16px;
display: block;
color: #656565;
}
header .sub-menu ul.menu li a:hover {
color: #000;
}
header .sub-menu .search {}
header .sub-menu .search input {}
header .sub-menu .search .material-icons {}
/* 이렇게 미리 작성해서 HTML 구조에 따라 코드를 더하는 방법도 좋다 */
before
가상요소선택자로 서브메뉴 사이 창살을 만들었음 block요소로 만들어 줄로 표현했음 제일 신기했음 게다가 before
특성상 맨 앞줄에도 창살이 있는데 first-child
의 none
으로 없애서 입이 쩍~li a
선택자의 클릭 폭을 글자보다 늘려 쉽게 클릭하게 만드는 방법에서 나타남검색 박스의 형태와 위치를 지정, 주의할 점은 배치를 잘 했어도 완성본처럼 구글의 아이콘이 없어지지 않거나 아이콘이 텍스트 박스 앞에 나와있어 클릭하기 어려움, 여기서부터 JS가 나옴!!! ㅠㅠ
header .sub-menu { /* 서브메뉴, 검색창 한 줄 배치 및 왼쪽 상단 정렬 */
position: absolute;
top: 10px;
right: 0;
display: flex;
}
header .sub-menu .search {
height: 34px;
position: relative;
}
header .sub-menu .search input {
width: 36px;
height: 34px;
padding: 4px 10px;
border: 1px soild #ccc;
box-sizing: border-box;
border-radius: 5px;
outline: none; /* 파란색 선이 나타나는데 수정하기 어려워 쓰지 않게 */
background-color: #fff;
color: #777;
font-size: 12px;
transition: width .4s;
}
header .sub-menu .search input:focus { /* 눌렀을 때 변화 */
width: 190px;
border-color: #669900;
}
header .sub-menu .search .material-icons {
height: 24px; /* 구글의 머터리얼 아이콘 크기와 같음 */
position: absolute;
top: 0;
bottom: 0;
right: 5px;
margin: auto;
transition: .4s; /* js 코드 추가 이후 추가 코드 */
}
header .sub-menu .search.focused .material-icons {
opacity: 0;
} /* js로 focused를 붙히면 아이콘 없어지는 코드! */
★코딩 작성 전 HTML에 연결 必
// HTML 코드 작성 : <script defer src="./js/main.js"></script> <!--defer 필수!-->
// 검색창 요소(.search) 찾기.
const searchEl = document.querySelector('.search');// search 클래스 데려오기
const searchInputEl = searchEl.querySelector('input');
searchEl.addEventListener('click', function () {
searchInputEl.focus();
});
// 1. .search의 요소 클릭 2. 포커스됨 3. input 요소도 같이 포커스됨
searchInputEl.addEventListener('focus', function () {
searchEl.classList.add('focused'); // focused 클래스 추가
searchInputEl.setAttribute('placeholder', '통합검색');
});
// 1. input 포커스되면 2. focused 붙힘 3. input 요소에 통합검색 붙힘
searchInputEl.addEventListener('blur', function () {
searchEl.classList.remove('focused'); // 클래스 없애기
searchInputEl.setAttribute('placeholder', ''); // placeholder 없애기
});
// 1. input 블러되면 2. 지움 3. 없앰
searchEl
이라는 변수를 둬 그 안 input
태그 선택자로만 찾게 작성변수.focus()
: JS를 통해 input
같이 포커스가 가능한 요소와 함께 강제로 포커스하게 만듬.setAttribute('속성', '속성값')
: 그 태그 안에 속성과 속성값을 집어 넣음, 위 코드는 focus
되면 '통합검색'이 나오도록 설정했음.focused
를 추가해 CSS에 추가적인 설정 가능 : .search.focused
focus
의 반댓말은 blur
임, 포커스가 빠지면 블러된다!※ 핸들러 복습 : 'click / focus...
' 되면 함수 실행
대표적인 메뉴들과 마우스를 갖다 댔을 때 드롭다운 메뉴가 나오도록 설정.
2개의 줄이 나오고 위의 로고부터 검색창까지의 영역을 메인메뉴도 똑같이 쓰고 있음.
.sub-menu
아래 형제 클래스로 위치해서 코드 작성
<ul class="main-menu"> <!--메인메뉴 및 드롭다운 메뉴 클래스, 이름, 내용 설정-->
<li class="item">
<div class="item__name">COFFEE</div>
<div class="item__contents"> <!--언더바 2개 이유가 있음-->
<div class="contents__menu">
<ul class="inner">
<li>
<h4>커피</h4>
<ul>
<li>스타벅스 원두</li>
<li>스타벅스 비아</li>
<li>스타벅스 오리가미</li>
</ul>
</li>
<li>
<h4>에스프레소 음료</h4>
<ul>
<li>도피오</li>
<li>에스프레소 마키아또</li>
<li>아메리카노</li>
<li>마키아또</li>
<li>카푸치노</li>
<li>라떼</li>
<li>모카</li>
<li>리스트레또 비안코</li>
</ul>
</li>
<li>
<h4>커피 이야기</h4>
<ul>
<li>스타벅스 로스트 스팩트럼</li>
<li>최상의 아라비카 원두</li>
<li>한 잔의 커피가 완성되기까지</li>
<li>클로버® 커피 추출 시스템</li>
</ul>
</li>
<li>
<h4>최상의 커피를 즐기는 법</h4>
<ul>
<li>커피 프레스</li>
<li>푸어 오버</li>
<li>아이스 푸어 오버</li>
<li>커피 메이커</li>
<li>리저브를 매장에서 다양하게 즐기는 법</li>
</ul>
</li>
</ul>
</div>
<div class="contents__texture">
<div class="inner">
<h4>나와 어울리는 커피 찾기</h4>
<p>스타벅스가 여러분에게 어울리는 커피를 찾아드립니다.</p>
<h4>최상의 커피를 즐기는 법</h4>
<p>여러가지 방법을 통해 다양한 풍미의 커피를 즐겨보세요.</p>
</div>
</div>
</div>
</li>
p
로 쓴 것이 있는데 div
로 써도 무방, 그저 문장으로 쓴다고 명확하게 지정한 것뿐a
태그로!/* COMMON */
/* INNER */
.inner {
width: 1100px;
margin: 0 auto; /* auto를 써 브라우저가 계산, 좌우 */
position: relative;
}
/* HEADER */
header > .inner {
height: 120px;
}/* 로고와 서브메뉴의 높이가 120px */
header .main-menu {
position: absolute;
bottom: 0;
right: 0;
z-index: 1; /* 배너나 배경보다 제일 앞에 나오도록 */
display: flex;
}
header .main-menu .item .item__name {
padding: 10px 20px 34px 20px;
font-family: Arial, sans-serif;
font-size: 13px;
}
header .main-menu .item:hover .item__name {
background-color: #2c2a29;
color: #669900;
border-radius: 6px 6px 0 0;
} /* contents, name 둘다 나와야해서 item에 hover를 줌 */
header .main-menu .item .item__contents {
width: 100%;
position: fixed;
left: 0;
display: none;
} /* 배치를 뷰포트 기준으로 해서 화면 양옆 끝까지 가게끔 + 기준을 왼쪽 0으로 */
header .main-menu .item:hover .item__contents {
display: block;
}
header .main-menu .item .item__contents .contents__menu {
background-color: #2c2a29;
}
header .main-menu .item .item__contents .contents__menu > ul {
display: flex; /* inner가 수평정렬 할 수 있도록 */
padding: 20px 0;
} /* ul안 ul안 ul.. 이 될 수 있어서 제대로 지정(inner)해야함 */
header .main-menu .item .item__contents .contents__menu > ul > li {
width: 220px;
} /* 커피 */
header .main-menu .item .item__contents .contents__menu > ul > li h4 {
padding: 3px 0 12px 0;
font-size: 14px;
color: #fff;
} /* 스타벅스~ */
header .main-menu .item .item__contents .contents__menu > ul > li ul li {
padding: 5px 0;
font-size: 12px;
color: #999;
cursor: pointer; /* 커서가 위로 올라왔을때 클릭 버튼으로 되는 속성 */
}
header .main-menu .item .item__contents .contents__menu > ul > li ul li:hover {
color: #669900;
}
header .main-menu .item .item__contents .contents__texture {
padding: 26px 0;
font-size: 12px;
background-image: url("../images/main_menu_pattern.jpg");
} /* 배경 이미지 패턴은 작지만 기본값인 이미지 반복으로 설정돼있음 */
header .main-menu .item .item__contents .contents__texture h4 {
color: #999;
font-weight: 700;
}
header .main-menu .item .item__contents .contents__texture p {
color: #669900;
margin: 4px 0 14px;
}
header .inner
부분을 헤더나 메인메뉴 등 많이 쓰일거기에 공통 코드 부분으로 옮김, 높이만 다르게 설정할 수 있어야하기에 height
만 빼고 적음header .inner
부분에 height: 120px;
만 남겨두고 공통 코드로 철수, 특히 ul
, li
태그 활용할 때 구조가 ul
안 또다른 ul
이 있을 확률이 크기 때문에 많이 쓴다 ★ 다른 header의 inner에게 영향 주지 않기 위해 자식 선택자 >
를 활용hover
선택자를 중간 .item
에 넣는 경우는 속성 남용x, .item
에 hover를 줘 다른 속성이 쓸때 그 설정을 계승시켜 편하게 쓰기 위함이 있다.../
을 하면 CSS 파일이 위치한 파일 위치의 밖의 폴더부터 시작! 복습하자HTML 구조를 세울때 클래스 이름을 잘 정해서 어떤 구조가 반복될지 먼저 생각하고 CSS 코드를 작성하기!
잘 작성하면 HTML에 무슨 내용을 추가하든 다 같은 디자인으로 나옴
헤더 아래 부분 나오는 배너를 뜻함, 드롭다운 메뉴가 나올 때 배지가 가려져야하므로 비쥬얼 섹션에 있지만 드롭다운 메뉴하면서 같이 신경쓰며 만들자.
<div class="badges">
<div class="badge">
<img src="./images/badge1.jpg" alt="Badge" />
</div>
<div class="badge">
<img src="./images/badge2.jpg" alt="Badge" />
</div>
</div>
배너가 2개이니 .badges
아래 .badge
2개의 구조를 가짐
header {
width: 100%;
/* position: relative; */
background-color: #f6f5f0;
border-bottom : 1px soild #c8c8c8;
position: fixed;
top: 0;
}
header .badges {
position: absolute;
top: 132px;
right: 12px;
}
header .badges .badge {
border-radius: 10px;
overflow: hidden; /* 넘치지 않게 */
margin-bottom: 12px;
box-shadow: 4px 4px 10px rgba(0,0,0,.15);
cursor: pointer;
}
.header
에 position
기준이 없어서 코드 추가 후 .header
에 메인메뉴가 위에 고정되게 배치를 fixed
하는데 기본값 auto를 쓰면 메뉴들이 축소되기때문에 100%를 써줌
const badgeEl = document.querySelector('header .badges');
// lodash 라이브러리를 통해 등록 후 여기서 사용
window.addEventListener('scroll', _.throttle(function () {
console.log(window.scrollY);
if (window.scrollY > 500) {
// 배지 숨기기
// gsap.to(요소, 지속시간, 옵션-객체데이터);
gsap.to(badgeEl, .6, {
opacity: 0,
display: 'none'
});
} else {
// 배지 보이기
gsap.to(badgeEl, .6, {
opacity: 1
display: 'block'
});
}
}, 300)); // 300 ms라는 뜻, 0.3초마다 실행되게!
// _.throttle(함수() {}, 시간)
※window: 윈도우 객체, 윈도우 창을 뜻함, 우리가 보는 화면 자체
addEventListener
에 scroll
을 그냥 추가해 사용하면 스크롤 할때마다 함수가 실행돼서 부담이 커짐 - lodash 라이브러리 활용해 제어해야함, scroll에 이벤트 추가할 때 권장사항임script
tag 복사 - JS 파일 script
코드 바로 위에 작성scrollY
: 스크롤 될 때마다 윈도우의 객체 부분의 속성 Y의 값이(스크롤의 위치 몇픽셀) 갱신되는 걸 알려줌script
추가to
라는 기능을 사용gsap.to(badgeEl, .6, {객체데이터}
: badgeEl
을 0.6초동안 바뀌도록 설정함opacity: 0
으로 처리해 투명하게 하면서 display: 'none'
을 사용해 클릭조차 안되게 만듦display
값만 사용하면 중간값이 없기에 자연스러운 전환 효과 사용이 어려움. 그래서 같이 써주면 자연스러우면서도 아예 없애기 가능그동안 Header를 작성했다. 그 다음은 Header의 아래 음료가 순차적으로 나오는 이미지와 비쥬얼의 Section을 구현하자!
<!-- VISUAL -->
<section class="visual">
<div class="inner">
<div class="title">
<img src="./images/visual_title.png" alt="STARBUCKS DELIGHTFUL START TO THE YEAR" />
<a href="javascript:void(0)" class="btn btn--brown">자세히 보기</a>
</div>
<img src="./images/visual_cup1.png" alt="new OATMEAL LATTE" class="cup1 image" />
<img src="./images/visual_cup1_text.png" alt="오트밀 라떼" class="cup1 text" />
<img src="./images/visual_cup2.png" alt="new STARBUCKS CARAMEL CRUMBLE MOCHA" class="cup2 image" />
<img src="./images/visual_cup2_text.png" alt="스타벅스 카라멜 크럼블 모카" class="cup2 text" />
<img src="./images/visual_spoon.png" alt="Spoon" class="spoon" />
</div>
</section>
section
태그는 div
와 header
같이 의미는 없지만 영역 설정과 프로그래머가 따로 보기 쉽게 작성하는 태그임.javascript:void(0)
서브메뉴에서 했듯이 임시로 넣는 주소.btn
으로 따로 만들어야함, BEM 방식으로 btn--XXX로 다양한 스타일 적용 가능/* COMMON, 전역 */
/* BUTTON */
.btn {
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;
display: block;
transition: .4s;
} /* 우선순위 점수 : 10점 */
.btn:hover {
background-color: #333;
color: #FFF;
} /* btn이 reverse 되면 #333 색이 된다. 이렇게 상태를 설정해줘 우선순위 점수 20점을 얻어 나중에 따로 덮어써서 수정할 수 있음 */
.btn.btn--reverse {
background-color: #333;
color: #FFF;
}
.btn.btn--reverse:hover {
background-color: transparent;
color: #333;
}
.btn.btn--brown {
color: #592B18;
border-color: #592B18;
}
.btn.btn--brown:hover {
color: #FFF;
background-color: #592B18;
}
.btn.btn--gold {
color: #D9AA8A;
border-color: #D9AA8A;
}
.btn.btn--gold:hover {
color: #FFF;
background-color: #D9AA8A;
}
.btn.btn--white {
color: #FFF;
border-color: #FFF;
}
.btn.btn--white:hover {
color: #333;
background-color: #FFF;
}
/* VISUAL */
.visual {
margin-top: 120px; /* 헤더 부분 아래에 위치하도록 설정 */
background-image: url("../images/visual_bg.jpg");
background-position: center;
}
.visual .inner {
height: 646px;
} /* inner의 공통 속성 적용돼서 따로 코드 작성 X */
.visual .title {
position: absolute;
top: 88px;
left: -10px;
}
.visual .title .btn {
position: absolute;
top: 259px;
left: 173px;
} /* title에 btn 클래스를 붙여 title의 이미지와 버튼이 함께 움직이도록 설정 */
.visual .cup1.image {
position: absolute;
bottom: 0;
right: -47px;
} /* 일치선택자 */
.visual .cup1.text {
position: absolute;
top: 38px;
right: 162px;
}
.visual .cup2.image {
position: absolute;
bottom: 0;
right: 162px;
}
.visual .cup2.text {
position: absolute;
top: 321px;
right: 416px;
}
.visual .spoon {
position: absolute;
bottom: 0;
left: 275px;
}
.btn
을 작성class= "btn btn--XXX"
하고 작성하면 됨header .main-menu .item .item__contents .contents__texture
: 모든 구조를 나타낸 선택자.visual (.inner .title) .cup1.image
: inner
를 다 안써주고 .title
만 써준 선택자position: absolute;
로 설정돼있어서 그 부모인 title
에 기준하여 그 위치에서 top: 259px;
, left: 173px;
즉! 위에서 259px 만큼 아래, 왼쪽에서 173px 만큼 와서 위치한다! 라는 뜻, 이미지 보면서 직관적으로 이해하기!------------------------------------------여기서부터 4주차------------------------------------------
음료 이미지들이 순차적으로 나오도록 환경 설정한다. 지금까지 그냥 나오도록 설정 및 배치한 코드라면 이제부터는 각 요소마다 fade in, out 되도록, 순차적으로 나오도록 작성하자
<div class="title fade-in">
<img src="./images/visual_title.png" alt="STARBUCKS DELIGHTFUL START TO THE YEAR" />
<a href="javascript: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 CARAMEL 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>
.fade-in
이라는 클래스 작성 및 수정 해줌.visual .fade-in {
opacity: 0;
}
.fade-in
에 투명도 0을 넣어줘 fade-in이 되면 투명하게 보이게 설정// 나타날 요소들(.fade-in) 찾기.
const fadeEls = document.querySelectorAll('.visual .fade-in')
// 나타날 요소들을 하나씩 반복해서 처리!
fadeEls.forEach(function (fadeEl, index) { // 반복 사용, 순서 정의
// 각 요소들을 순서대로(delay) 보여지게 함!
gsap.to(fadeEl, 1, {
delay: (index + 1) * .7,
opacity: 1
})
})
index
로 0부터 반복하는 함수를 만듦(Zero-based Numbering)delay
함수 해석 : index에 1을 더해 첫번째 요소(fadeEl
)에는 0.7초 후에 투명도(opacity
)가 1이 되고 두번째 요소는 1.4초 후에, 세번째는 2.1초 후에 ... 하고 반복됨! index가 0부터 시작하므로 1을 더하는 디테일 잘 봐야함!반복을 몰랐다면 0.7, 1.4 ... 이렇게 일일이 설정해야한다 이런 건 피해야한다! 다양한 구조 처리를 미리 알자!
그 다음 Section으로 공지사항 및 프로모션 등등을 만들 것
Swiper 라이브러리를 활용해 수직 슬라이드를 만들어 보자
Swiper JS : 슬라이드를 만들수 있는 라이브러리
기본 구조 :.swiper-container
=>.swiper-wrapper
=>.swiper-slide
=>.a
등의 태그나 내용 작성
<!--NOTICE-->
<section class="notice">
<!--NOTICE LINE-->
<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 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">
<a href="javascript:void(0)">[당첨자 발표] 뉴이어 전자영수증 이벤트</a>
</div>
</div>
</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>
/*NOTICE*/
/*NOTICE LINE*/
.notice .notice-line {
position: relative;
}
.notice .notice-line .bg-left {
position: absolute;
top: 0;
left: 0;
width: 50%;
height: 100%;
background-color: #333;
} /* bg-left, right는 width가 브라우저 끝까지 가게 만드는 선택자 */
.notice .notice-line .bg-right {
position: absolute;
top: 0;
right: 0;
width: 50%;
height: 100%; /* 설정된 높이 100% */
background-color: #f6f5ef;
}
.notice .notice-line .inner {
height: 62px;
z-index: 1;
display: flex;
}
.notice .notice-line .inner__left {
width: 60%;
height: 100%;
background-color: #333;
display: flex;
align-items: center;
}
.notice .notice-line .inner__left h2 {
color: #fff;
font-size: 17px;
font-weight: 700;
margin-right: 20px;
}
.notice .notice-line .inner__left .swiper-container {
flex-grow: 1;
height: 62px;
} /* 얘만 grow가 1이여서 형제가 갖고 있는 크기를 빼고 설정된 크기만큼 stretch됨 */
/* Swiper 라이브러리 추가 이후 추가 작성 */
.notice .notice-line .inner__left .swiper-slide {
height: 62px;
display: flex;
align-items: center;
}
.notice .notice-line .inner__left .swiper-slide a {
color: #fff;
}
.notice .notice-line .inner__left .notice-line__more {
width: 62px;
height: 62px;
display: flex; /* 가운데 정렬을 위함 */
justify-content: center; /* 수평 가운데 정렬 */
align-items: center; /* 수직 가운데 정렬 */
}
.notice .notice-line .inner__left .notice-line__more .material-icons {
color: #fff;
font-size: 30px;
} /* 아이콘의 기본 크기는 24px */
.notice .notice-line .inner__right {
width: 40%;
height: 100%;
display: flex;
justify-content: flex-end; /* 아이템들을 끝점으로 정렬 */
align-items: center;
}
.notice .notice-line .inner__right h2 {
font-size: 17px;
font-weight: 700;
}
.notice .notice-line .inner__right .toggle-promotion {
width: 62px;
height: 62px;
cursor: pointer;
display: flex; /* 가운데 정렬을 위함 */
justify-content: center; /* 수평 가운데 정렬 */
align-items: center; /* 수직 가운데 정렬 */
}
.notice .notice-line .inner__right .toggle-promotion .material-icons {
font-size: 30px;
}
.notice-line
이 부모지만 width
, height
값이 따로 없어 형제인 .inner
(COMMON의 스타일도 포함)로 높이가 제어됨, 즉 .inner
하나로 일일이 각각의 선택자에 높이를 입력 안해도 됨flex-grow
복습: 부모에 플렉스를 부여했을때 숫자 등을 지정해 비율을 정하는 것, 설정된 비율만큼 좌우, 높이 다 최대한 stretch됨flex
에서 쓰이는 정렬법 복습: flex-end
, justify
, align
등등/* 슬라이드 요소 관리 */
// new Swiper('선택자', {옵션}); Swiper라는 기능을 추가한다.
new Swiper('.notice-line .swiper-container', {
direction: 'vertical', // 수직 슬라이드
autoplay: true, // 자동 재생 여부: 불린 데이터로 결정
loop: true // 반복 재생 여부: 불린 데이터로 결정
});
new
는 JS에서 생성자(클래스)를 뜻함, 위 코드에 new
는 Swiper라는 함수를 실행한다~ 하고 선언으로 쓰임이벤트나 광고 등을 넣을 수 있는 수평 슬라이드를 만들자!
자세히 보기, 이미지를 확대·축소시켜도 정 가운데 유지
<!--PROMOTION-->
<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">
<span class="material-icons">arrow_back</span>
</div>
<div class="swiper-next">
<span class="material-icons">arrow_forward</span>
</div>
</div>
</div>
slide의 광고, 이벤트 이미지와 '자세히보기' 배치 및 꾸미기, 페이지네이션 불렛, 애로우 배치와 꾸미기
.notice .promotion {
height: 693px;
background-color: #f6f5ef;
position: relative;
}
.notice .promotion .swiper-container {
width: calc(819px * 3 + 20px);
height: 553px;
position: absolute;
top: 40px;
right: 50%;
margin-right: calc((819px * 3 + 20px) / -2);
} /* width의 크기 절반을 기준으로 삼은 다음 margin-XX로 땡겨오기 */
.notice .promotion .swiper-slide {
opacity: .5;
transition: opacity 1s;
position: relative;
}
.notice .promotion .swiper-slide-active {
opacity: 1;
}
.notice .promotion .swiper-slide .btn {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin: auto;
} /* 버튼의 배치 */
.notice .promotion .swiper-pagination {
bottom: 40px;
left: 0;
right: 0;
} /* 라이브러리에 포지션 값이 이미 할당돼있어서 이렇게 작성, 브라우저로 검사 눌러서 확인해보기! */
.notice .promotion .swiper-pagination .swiper-pagination-bullet {
background-color: transparent; /* 투명으로 채움, 기본은 파란색으로 채워짐 */
background-image: url("../images/promotion_slide_pager.png");
width: 13px;
height: 12px;
margin-right: 6px;
outline: none; /* 파란색 테두리 선 출력 X */
} /* 페이지 번호의 불렛들을 디자인 */
.notice .promotion .swiper-pagination .swiper-pagination-bullet:last-child {
margin-right: 0;
} /* 불렛의 margin-right에 6px을 적어 여백을 줬는데 마지막 불렛에는 필요없어서 가상 클래스를 이용해 없앰 */
.notice .promotion .swiper-pagination .swiper-pagination-bullet-active {
background-image: url("../images/promotion_slide_pager_on.png");
} /* 활성화된 불렛은 active가 붙는다. 그걸 이용해 이미지 삽입으로 하이라이트! */
.notice .promotion .swiper-prev, /* 다중 선택자, 쉼표로 선택자 2개 해당되게 */
.notice .promotion .swiper-next { /* 줄바꿈 해주기! 직관적으로 보기 위해 */
width: 42px;
height: 42px;
border: 2px solid #333;
border-radius: 50%; /* 원 */
position: absolute;
/* Swiper Container 높이의 절반만큼 끌어올림 */
/* 버튼 높이의 절반만큼 추가로 끌어올림 */
top: 300px;
z-index: 1;
cursor: pointer;
outline: none;
display: flex; /* 화살표가 정 가운데로 가도록 만들기 */
justify-content: center; /* 수평 */
align-items: center; /* 수직 */
transition: .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 {
background-color: #333;
color: #fff;
}
.swiper-container
는 프로모션이 나타나는 크기를 먼저 정해야함. XXpx로 지정하기엔 틀릴 수도 있고, 나중에 수정으로 변했을 때 일일이 수정해야함. 그럴때 속성: calc()
함수를 씀!!calc()
의 예 : XXpx * X + XXpx / 100% - 50px(자주!)left
말고 right
를 써도 어느 부분(left를 right로)에서 뺄건지만 차이를 두고 나머진 같음!/**
* 슬라이드 요소 관리
*/
// new Swiper('선택자', {옵션}); Swiper라는 기능을 추가한다.
new Swiper('.notice-line .swiper-container', {
direction: 'vertical', // 수직 슬라이드
autoplay: true, // 자동 재생 여부: 불린 데이터로 결정
loop: true // 반복 재생 여부: 불린 데이터로 결정
});
new Swiper('.promotion .swiper-container', {
// direction: 'horizontal', // 수평 슬라이드
autoplay: { // 자동 재생 여부
delay: 5000 // 5초마다 슬라이드 바뀜
},
loop: true, // 반복 재생 여부
slidesPerView: 3, // 한 번에 3개 보여줌!
spaceBetween: 10, // 슬라이드 사이 여백
centeredSlides: true, // 1번 슬라이드가 가운데 보이기
pagination: { // 페이지 번호 사용 여부
el: '.promotion .swiper-pagination', // 페이지 번호 요소 선택자
clickable: true // 사용자의 페이지 번호 요소 제어 가능 여부
},
navigation: { // 슬라이드 이전/다음 버튼 사용 여부
prevEl: '.promotion .swiper-prev', // 이전 버튼 선택자
nextEl: '.promotion .swiper-next' // 다음 버튼 선택자
}
});
direction: 'horizontal'
이 기본값이라 수평 슬라이드할 땐 따로 안적어줘도 됨!.swiper-slide-active
을 이용해 메인으로 보여지는 슬라이드 빼고 반투명하게 만듦! 사용자가 가운데만 집중이 되게!'스타벅스 프로모션'의 슬라이드 버튼을 누르면 프로모션 슬라이드가 닫히고 열리는 걸 만들어본다!
HTML은 이미 promotion할 때 만들어 놨음!
<div class="toggle-promotion">
<div class="material-icons">upload</div>
</div>
.notice .promotion {
transition: height .4s;
overflow: hidden;
}
.notice .promotion.hide {
height: 0;
}
hide
를 가지고 활용height: 0;
으로 설정해 수직적으로 수축되게 만듬.notice .promotion
에 매끄럽게 변화를 만들기 위해 .4s를 붙이고 height
가 0이 된다면 그 전에 있던 promotion 요소들이 그대로 흘러넘치기 때문에 overflow: hidden;
로 설정/**
* Promotion 슬라이드 토글 기능, CSS에 활용할 클래스 만들기
*/
// 슬라이드 영역 요소 검색 및 변수 할당
const promotionEl = document.querySelector('.promotion');
// 슬라이드 영역를 토글하는 버튼 검색 및 변수에 할당
const promotionToggleBtn = document.querySelector('.toggle-promotion');
// 슬라이드 영역 숨김 여부 기본값을 false로 할당
let isHidePromotion = false;
// 토글 버튼을 클릭하면,
promotionToggleBtn.addEventListener('click', function () { // 이벤트 핸들러
// 슬라이드 영역 숨김 여부를 느낌표를 써 반댓값으로 할당!
isHidePromotion = !isHidePromotion
// 요소를 숨겨야 하면,
if (isHidePromotion) {
promotionEl.classList.add('hide')
// 요소가 보여야 하면,
} else {
promotionEl.classList.remove('hide')
}
});
.hide
를 추가 및 제거이제부터 리워즈 Section 시작! 유튜브 영상을 감쌀 버튼과 이미지를 배치한다!
<!--REWARDS-->
<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>
.bg-XX
로 영역 전개, .inner
로 버튼을 취합하여 정렬, .btn
을 활용한 디자인 구조를 만듦!/*REWARDS*/
.rewards {
position: relative;
}
.rewards .bg-left,
.rewards .bg-right{
width: 50%;
height: 100%;
position: absolute;
top: 0;
}
.rewards .bg-left {
background-color: #272727;
left: 0;
}
.rewards .bg-right {
background-color: #d5c798;
right: 0;
}
.rewards .inner {
background-image: url("../images/rewards.jpg");
height: 241px;
}
.rewards .btn-group {
position: absolute; /* COMMON의 inner에 relative 들어가있음 */
right: 0;
bottom: 24px;
width: 250px;
display: flex;
flex-wrap: wrap;
}
.rewards .btn-group .btn.sign-up {
/*width: 130px;*/
margin-right: 10px;
}
.rewards .btn-group .btn.sign-in {
width: 110px;
}
.rewards .btn-group .btn.gift {
margin-top: 10px;
flex: 1; /* 최대한의 너비를 사용하라 */
}
flex-wrap: wrap;
을 이용해 만듦영상 비율 맞추는 법!
이런 식으로padding-top
속성을 이용한다면 자연스럽게 화면 비율을 자동으로 계산해줘 편하다! 위는 16:9 비율로 작성됐다!
<script defer src="./js/youtube.js"></script>
<!--YOUTUBE VIDEO-->
<section class="youtube">
<div class="youtube__area">
<!-- Youtube iframe API 생성 id div -->
<div id="player"></div>
</div>
<div class="youtube__cover"></div>
</section>
id="player"
구조로 건설하고 cover를 따로 작성/*YOUTUBE VIDEO*/
.youtube {
position: relative;
height: 700px;
background-color: #333;
overflow: hidden;
}
.youtube .youtube__area {
width: 1920px;
position: absolute;
/* 16비율, 가로 */
left: 50%; /* 50% 위치 후 끌어오게 만드는 배치 방법 복습 */
margin-left: calc(1920px / -2);
/* 9비율, 세로 */
top: 50%;
margin-top: calc(1920px * 9 / 16 / -2); /* 폭 나누기 16:9 비율 나누기 중간에 위치토록 -2 */
}
.youtube .youtube__area::before {
content: "";
display: block;
/* 16:9 영상 비율로 요소 크기 만들기! */
width: 100%;
height: 0;
padding-top: 56.25%;
}
.youtube .youtube__cover {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,.3);
background-image: url("../images/video_cover_pattern.png");
} /* 유튜브 주변 커버 덮기 */
#player {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
left
와 top
으로 가운데 위치, 특히 top
은 1080px이지만 calc()
함수를 이용해서 * 9 / 16으로 세로비율을 맞췄음/* youtube.js 라는 파일을 따로 만들기
* 2. Youtube IFrame API를 비동기로 로드합니다.
*/
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
/* onYouTubePlayerAPIReady 함수 이름은,
* Youtube IFrame Player API에서 사용하는 이름이기 때문에,
* 다르게 지정하면 동작하지 않습니다!
* 그리고 함수는 전역(Global) 등록해야 합니다!
*/
function onYouTubeIframeAPIReady() {
// <div id="player"></div>
new YT.Player('player', {
videoId: 'An6LvWQuj_8', // 최초 유튜브 영상 ID, 주소창에 v= 이후 부분
playerVars: {
autoplay: true, // 자동 재생 유무
loop: true, // 반복 재생 유무
playlist: 'An6LvWQuj_8' // 반복 재생할 유튜브 영상 ID 목록
},
events: {
// 영상이 준비되었을 때,
onReady: function (event) {
event.target.mute() // 음소거!
}
}
});
}
요소들을 띄우고 각 요소가 따로 부유하는 듯한 느낌을 주기 위해서 랜덤 함수를 사용!
<div class="youtube__cover"></div>
<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
의 자식으로 입력.youtube .inner {
height: 700px;
} /* 임시로 배치 */
.youtube .floating1 {
position: absolute;
top: 50px;
left: 0;
}
.youtube .floating2 {
position: absolute;
top: 350px;
left: 150px;
}
.youtube .floating3 {
position: absolute;
bottom: -200px;
right: 0;
}
.floating3
가 잘려서 그다음 섹션에서 고쳐야함! 그래서 .inner
에 임의로 입력됐음// 범위 랜덤 함수, min이상 max이하 숫자 랜덤
function random(min, max) {
return parseFloat((Math.random() * (max - min) + min).toFixed(2))
}
function floatingObject(selector, delay, size) { // 딜레이, 사이즈 작성은 명확히 하기 위함
// gsap.to(요소, 시간, {옵션});
gsap.to(
selector, // 요소: 선택자
random(1.5, 2.5), // 동작 시간
{
delay: random(0, delay), // 시작 지연 시간을 설정, 단위: s
y: size, // `transform: translateY(수치);`와 같음. 수직으로 얼마나 움직일지 설정
repeat: -1, // `-1`은 무한 반복
yoyo: true, // 한번 재생된 애니메이션을 다시 뒤로 재생
ease: Power1.easeInOut // Easing In Out 함수 적용
}
)
}
floatingObject('.floating1', 1, 15);
floatingObject('.floating2', .5, 15);
floatingObject('.floating3', 1.5, 20); // 실행
// 숫자들은 위에 각각 delay, size로 들어간다!
TweenMax.to(=gsap.to)(요소명, 시간, {ease: Power1.easeOut});
이런식으로 적용하면 됨!// 범위 랜덤 함수(소수점 2자리까지)
function random(min, max) {
// `.toFixed()`를 통해 반환된 문자 데이터를,
// `parseFloat()`을 통해 소수점을 가지는 숫자 데이터로 변환
return parseFloat((Math.random() * (max - min) + min).toFixed(2))
}
※ https://greensock.com/docs/v3/GSAP/gsap.to() 사이트에 들어가서 객체데이터에 들어가는 gsap.to()만의 옵션들을 보고 입력하고 공부하기! 좋은 라이브러리임
유튜브 섹션 아래 또다른 이미지 섹션 3개 제작
- SEASON PRODUCT : 이 섹션에
.floating3
가 짤리기에 같이 수정 必- RESERVE COFFEE
- PICK YOUR FAVORITE
<!--SEASON PRODUCT-->
<section class="season-product">
<div class="inner">
<img src="./images/floating3.png" alt="Icon" class="floating floating3" />
<img src="./images/season_product_image.png" alt="아이스 커피 블렌드" class="product" />
<div class="text-group">
<img src="./images/season_product_text1.png" alt="상쾌하게 여름을 반겨줄 시즌 원두 아이스 커피 블렌드" class="title" />
<img src="./images/season_product_text2.png" alt="아프리카와 라틴 아메리카 커피의 브렌드로 시트러스함과 은은한 캐러멜 향을 동시에 느낄 수 있으며, 차갑게 즐길 때 풍미가 더욱 깊어지는 원두입니다." class="description" />
<div class="more">
<a href="javascript:void(0)" class="btn">자세히 보기</a>
</div>
</div>
</div>
</section>
<!--RESERVE COFFEE-->
<section class="reserve-coffee">
<div class="inner">
<img src="./images/reserve_logo.png" alt="" class="reserve-logo" />
<div class="text-group">
<img src="./images/reserve_text.png" alt="" class="description" />
<div class="more">
<a href="javascript:void(0)" class="btn btn--gold">자세히 보기</a>
</div> <!--버튼이 잘 안보여 btn--gold로-->
</div>
<img src="./images/reserve_image.png" alt="" class="product" />
</div>
</section>
<!--PICK YOUR FAVORITE-->
<section class="pick-your-favorite">
<div class="inner">
<div class="text-group">
<img src="./images/favorite_text1.png" alt="PICK YOUR FAVORITE" class="title" />
<img src="./images/favorite_text2.png" alt="다양한 메뉴를 스타벅스에서 즐겨보세요." class="description" />
<div class="more">
<a href="javascript:void(0)" class="btn btn--white">자세히 보기</a>
</div>
</div>
</div>
</section>
.floating3
를 그대로 복사해서.inner
에 붙임/*SEASON PRODUCT*/
.season-product {
background-image: url("../images/season_product_bg.jpg");
}
.season-product .inner {
height: 400px;
}
.season-product .floating3 { /* 수정 必 */
position: absolute;
top: -200px; /* 배치 기준이 바뀌었기에 top로 수정 */
right: 0;
}
.season-product .text-group {
position: absolute; /* inner에 relative 할당 */
top: 110px;
right: 100px;
}
.season-product .text-group .title {
margin-bottom: 10px;
}
.season-product .text-group .description {
margin-bottom: 15px;
}
/*RESERVE COFFEE*/
.reserve-coffee {
background-image: url("../images/reserve_bg.jpg");
}
.reserve-coffee .inner {
height: 400px;
}
.reserve-coffee .reserve-logo {
position: absolute;
top: 110px;
left: 0;
}
.reserve-coffee .text-group {
position: absolute;
top: 124px;
left: 208px;
}
.reserve-coffee .product {
position: absolute;
top: 0;
right: 0;
}
/*PICK YOUR FAVORITE*/
.pick-your-favorite {
background-image: url("../images/favorite_bg.jpg");
background-repeat: no-repeat;
background-position: center;
background-attachment: fixed;
background-size: cover; /* 폭이 1920px로 늘어남 */
}
.pick-your-favorite .inner {
padding: 110px 0; /* 글 위아래 여백 */
}
.pick-your-favorite .text-group {
width: 362px; /* 제한 */
margin-left: 100px; /* 위치조정 */
display: flex;
justify-content: flex-end; /* 우측으로 끝맞춤 */
flex-wrap: wrap; /* 줄바꿈 가능 */
}
.pick-your-favorite .text-group .title {
margin-bottom: 40px;
}
.pick-your-favorite .text-group .description {
margin-bottom: 40px;
}
.floating3
수정 必, 기준이 바뀌니 top
, bottom
구별 꼭!background-attachment: fixed;
를 활용해 배경을 뷰포트에 고정시켜 스크롤해도 배경이 안움직이는 간단한 패럴랙스 효과 구현※ 위코드의 패럴랙스 효과 구현 해설
1. 배경 이미지 삽입
2. 배경 이미지 반복 x
3. 배경 이미지를 센터로 정렬
4. 배경 이미지를 뷰포트 기준으로 출력해 스크롤해도 움직이지 않게 고정
5. 배경 이미지가 왜곡이 일어나지 않는 한도 내까지 늘어나게 만들기
<!--RESERVE STORE-->
<section class="reserve-store">
<div class="inner">
<div class="medal">
<div class="front">
<img src="./images/reserve_store_medal_front.png" alt="R">
</div>
<div class="back">
<img src="./images/reserve_store_medal_back.png" alt="스타벅스 리저브 매장">
<a href="javascript:void(0)" class="btn">
매장안내
</a>
</div>
</div>
</div>
</section>
/*RESERVE STORE*/
.reserve-store { /* 패럴랙스 */
background-image: url("../images/reserve_store_bg.jpg");
background-repeat: no-repeat;
background-position: center;
background-attachment: fixed;
background-size: cover;
}
.reserve-store .inner {
height: 600px;
display: flex;
justify-content: center;
align-items: center;
}
.reserve-store .medal {
width: 334px;
height: 334px;
perspective: 600px; /* 자연스런 회전을 위해 원근감 부여 */
}
.reserve-store .medal .front,
.reserve-store .medal .back {
width: 334px;
height: 334px;
position: absolute;
transition: 1s;
backface-visibility: hidden; /* 뒷면은 화면 표시 x */
}
.reserve-store .medal .front {
transform: rotateY(0deg);
}
.reserve-store .medal:hover .front {
transform: rotateY(180deg);
}
.reserve-store .medal .back {
transform: rotateY(-180deg); /* 회전 방향을 설정위해 -를 붙임 */
}
.reserve-store .medal:hover .back {
transform: rotateY(0deg);
}
.reserve-store .medal .back .btn {
position: absolute;
top: 230px;
left: 0;
right: 0;
margin: auto;
}
:hover
, perspective
, transform: rotateY(+-180, 0deg);
, backface-visibility: hidden;
, transition
활용transform: rotateY(0deg);
은 안써줘도 되지만 명확히 표시 및 구형의 브라우저에서도 시작점을 명확히 알려 돌아가게끔 만들어줌.front
에서 0 - 180 .back
에서 180 - 0 방향을 자연스럽게 줘야하기에 .back
에서 -180도에서 출발 <!--FIND THE STORE-->
<section class="find-store">
<div class="inner">
<img src="./images/find_store_texture1.png" alt="" class="texture1" />
<img src="./images/find_store_texture2.png" alt="" class="texture2" />
<img src="./images/find_store_picture1.jpg" alt="" class="picture1" />
<img src="./images/find_store_picture2.jpg" alt="" class="picture2" />
<div class="text-group">
<img src="./images/find_store_text1.png" alt="스타벅스를 가까이에서 경험해보세요." class="title" />
<img src="./images/find_store_text2.png" alt="고객님과 가장 가까이 있는 매장을 찾아보세요!" class="description" />
<div class="more">
<a href="javascript:void(0)" class="btn">매장찾기</a>
</div>
</div>
</div>
</section>
/*FIND STORE*/
.find-store {
background-image: url("../images/find_store_bg.jpg");
}
.find-store .inner {
height: 400px;
}
.find-store .texture1 {
position: absolute;
top: 0;
left: 400px;
}
.find-store .texture2 {
position: absolute;
bottom: 0;
right: 0;
}
.find-store .picture {
border-radius: 50%; /* 원만들기 */
box-shadow: 2px 2px 8px 0 rgba(0,0,0,.5);
position: absolute;
}
.find-store .picture1 {
top: -60px;
left: 0;
}
.find-store .picture2 {
top: 150px;
left: 250px;
}
.find-store .text-group {
position: absolute;
top: 120px;
left: 550px;
}
.find-store .text-group .title {
margin-bottom: 20px; /* 제목 - 설명 여백 */
}
.find-store .text-group .description {
margin-bottom: 20px; /* 설명 - 버튼 여백 */
}
ScrollMagic JS 라이브러리 학습, 이런 것도 있구나~
/* COMMON */
/*BACK TO POSITION*/
.back-to-position {
opacity: 0;
transition: 1s;
}
.back-to-position.to-right {
transform: translateX(-150px);
}
.back-to-position.to-left {
transform: translateX(150px);
}
.show .back-to-position {
opacity: 1;
transform: translateX(0);
}
.show .back-to-position.delay-0 {
transition-delay: 0s;
}
.show .back-to-position.delay-1 {
transition-delay: .3s;
}
.show .back-to-position.delay-2 {
transition-delay: .6s;
}
.show .back-to-position.delay-3 {
transition-delay: .9s;
}
애니메이션 스타일 클래스 해설
.back-to-position
: 투명하게, 애니 1초.to-right / to-left
: 각각 -150px, 150px에서 출발점.show .back-to-position
: JS로.show
가 붙으면 원점(0)으로 이동하면서 불투명하게 변화.delay-N
: 애니 시작 딜레이를 줘 더욱 스타일리쉬한 효과 추가
/**
* 요소가 화면에 보여짐 여부에 따른 요소 관리
*/
// 관리할 요소들 검색!
const spyEls = document.querySelectorAll('section.scroll-spy');
// 요소들 반복 처리!
spyEls.forEach(function (spyEl) {
new ScrollMagic // 여기 생성자는 .XXXX = 메소드로 제어 중, 메소드가 길어지니 줄바꿈
.Scene({ // Scene(특정한 요소를 감시할 장면)을 추가
triggerElement: spyEl, // 보여짐 여부를 감시할 요소를 지정
triggerHook: .8 // 실행될 애니를 지금 보는 화면 0.8, 80% 지점에서 실행!
})
.setClassToggle(spyEl, 'show') // 토글: 넣다뺐다, 요소가 화면에 보이면 show 클래스 추가
.addTo(new ScrollMagic.Controller()); // 컨트롤러에 장면을 할당(필수!)
});
.show
클래스를 추가함!Awards 수평 슬라이드 만들기! Promotion 섹션 만들 때랑 비슷하다!
위에서 했던 수평 슬라이드를 만들고, 아이콘도 삽입하기
<!--AWARDS-->
<section class="awards">
<div class="inner">
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<img src="./images/awards_slide1.jpg" alt="대통령 표창" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide2.jpg" alt="대통령 표창 (3년 연속)" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide3.jpg" alt="우수사업주 인증" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide4.jpg" alt="경연대회 대상" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide5.jpg" alt="대한상의회장상" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide6.jpg" alt="기업사회공헌 활동 부문" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide7.jpg" alt="KSI 1위 (5년 연속)" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide8.jpg" alt="KS-SQI 1위 (5년 연속)" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide9.jpg" alt="커피전문점 부문 (4년 연속)" />
</div>
<div class="swiper-slide">
<img src="./images/awards_slide10.jpg" alt="동반성장 부문 (4년 연속)" />
</div>
</div>
</div>
<div class="swiper-prev">
<span class="material-icons">arrow_back</span>
</div>
<div class="swiper-next">
<span class="material-icons">arrow_forward</span>
</div>
</div>
</section>
.swiper-prev·next
를 만들기/*AWARDS*/
.awards {
background-color: #272727;
}
.awards .inner {
padding: 40px 0;
}
.awards .swiper-container {
width: 100%;
height: 40px;
}
.awards .swiper-prev,
.awards .swiper-next {
width: 42px;
height: 42px;
outline: none;
border: 2px solid #fff;
border-radius: 50%;
color: #fff;
position: absolute;
top: 0;
bottom: 0;
margin: auto;
opacity: .3;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
transition: .4s;
}
.awards .swiper-prev {
left: -100px;
}
.awards .swiper-next {
right: -100px;
}
.awards .swiper-prev:hover,
.awards .swiper-next:hover {
background-color: #fff;
color: #333;
}
width: 100%;
, 높이 디자인.swiper-prev·next
디자인과 .inner
의 위치 기준의 -100px로 배치new Swiper('.awards .swiper-container', {
// direction: 'horizontal', // 수평 슬라이드
autoplay: true, // 자동 재생 여부
loop: true, // 반복 재생 여부
spaceBetween: 30, // 슬라이드 사이 여백
slidesPerView: 5, // 한 번에 보여줄 슬라이드 개수
// slidesPerGroup: 5, // 한 번에 슬라이드 할 개수(전체 개수로 나뉘어야 함)
navigation: { // 슬라이드 이전/다음 버튼 사용 여부
prevEl: '.awards .swiper-prev', // 이전 버튼 선택자
nextEl: '.awards .swiper-next' // 다음 버튼 선택자
}
})
navigation:{prevEl·nextEl: '요소'}
를 통해 이전/다음 버튼 사용&XXX;
: HTML Entity
구글링, HTML에서 특수기호를 손으로 직접 치면 안나오는 경우가 있기 때문에(<,>,= 등등) XXX에 그 특수기호 이름이나 숫자를 써 특정한 코드를 작성해 그대로 화면에 출력되게 만드는 걸 배우자!
<!--FOOTER-->
<footer>
<div class="inner">
<ul class="menu">
<li><a href="javascript:void(0)" class="green">개인정보처리방침</a></li>
<li><a href="javascript:void(0)">영상정보처리기기 운영관리 방침</a></li>
<li><a href="javascript:void(0)">홈페이지 이용약관</a></li>
<li><a href="javascript:void(0)">위치정보 이용약관</a></li>
<li><a href="javascript:void(0)">스타벅스 카드 이용약관</a></li>
<li><a href="javascript:void(0)">윤리경영 핫라인</a></li>
</ul>
<div class="btn-group">
<a href="javascript:void(0)" class="btn btn--white">찾아오시는 길</a>
<a href="javascript:void(0)" class="btn btn--white">신규입점제의</a>
<a href="javascript:void(0)" class="btn btn--white">사이트 맵</a>
</div>
<div class="info">
<span>사업자등록번호 201-81-21515</span>
<span>(주)스타벅스 코리아 대표이사 이석구</span>
<span>TEL : 02) 3015-1100 / FAX : 02) 3015-1106</span>
<span>개인정보 책임자 : 강기원</span>
</div>
<p class="copyright">
© <span class="this-year"></span> Starbucks Coffee Company. All Rights Reserved.
</p>
<img src="./images/starbucks_logo_only_text.png" alt="STAR BUCKS" class="logo" />
</div>
</footer>
footer
태그로 시작!©
: 엠퍼센드으로 시작돼 세미콜론이 사용된 copy라는 HTML의 특수 기호, 해당하는 내용의 문자가 화면으로 출력됨! - ©.this-year
는 비어있지만 나중에 JS로 제어해서 연도를 나타낼거임!/*FOOTER*/
footer {
background-color: #272727;
border-top: 1px solid #333;
}
footer .inner {
padding: 40px 0 60px 0;
}
footer .menu {
display: flex;
justify-content: center;
} /* 메뉴 수평 정렬 */
footer .menu li {
position: relative;
}
footer .menu li::before { /* 가상요소선택자를 만들어 HTML에 각각 입력 안해도 됨! */
content: ""; /* 필수 */
width: 3px;
height: 3px;
background-color: #555;
position: absolute; /* block으로 바뀜 */
top: 0;
bottom: 0;
right: -1px;
margin: auto;
} /* 사이사이 점들 만들기 */
footer .menu li:last-child::before {
display: none;
} /* 끝에는 필요 없기에 :last-child라는 가상 선택자를 이용해 마지막껀 없앰 */
footer .menu li a {
display: block; /* 사용자가 클릭할 수 있는 영역을 더 넓혀주려고 block */
color: #CCC;
font-size: 12px;
font-weight: 700;
padding: 15px;
}
footer .menu li a.green {
color: #669900;
}
footer .btn-group {
margin-top: 20px;
display: flex;
justify-content: center;
}
footer .btn-group .btn {
font-size: 12px;
margin-right: 10px;
}
footer .btn-group .btn:last-child {
margin-right: 0;
}
footer .info {
margin-top: 30px;
text-align: center; /* 문자 가운데 정렬 */
}
footer .info span {
margin-right: 20px;
color: #999;
font-size: 12px;
}
footer .info span:last-child {
margin-right: 0;
} /* 우측 여백 삭제 */
footer .copyright {
color: #999;
font-size: 12px;
text-align: center; /* 텍스트는 text-align: center로 가운데 정렬 */
margin-top: 12px;
}
footer .logo {
margin: 30px auto 0; /* 이미지는 margin: auto로 가운데 정렬 */
}
.menu
, .btn
, .copyright
, .logo
요소들 배치/**
* 올해가 몇 년도인지 계산
*/
const thisYear = document.querySelector('.this-year')
thisYear.textContent = new Date().getFullYear()
ScrollTo는 기본 GSAB cdn에 없다. 왜냐하면 한 파일에 잡다한 기능까지 다 있으면 파일이 무거워져 렌더링하는데 로딩이 오래 걸린다. 그래서 필수 기능만 담고 나머지는 따로 불러와야하는데 대표적인게 ScrollTo다.
<!--TO TOP BUTTON-->
<div id="to-top">
<div class="material-icons">arrow_upward</div>
</div>
/*SCROLL TO TOP*/
#to-top {
position: fixed;
bottom: 30px;
right: 30px;
z-index: 9;
width: 42px;
height: 42px;
background-color: #333;
color: #fff;
border: 2px solid #fff;
border-radius: 10px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
z-index
값도 9로 설정에 맨 앞으로 배치const toTopEl = document.querySelector('#to-top')
// window: 윈도우 객체, 윈도우 창을 뜻함, 우리가 보는 화면 자체
window.addEventListener('scroll', _.throttle(function () { // lodash 라이브러리를 통해 등록 후 여기서 사용
console.log(window.scrollY);
if (window.scrollY > 500) { // 스크롤 될 때마다 윈도우의 객체 부분의 속성 Y의 값이(스크롤의 위치 몇픽셀) 갱신되는 걸 알려줌
// 상단으로 스크롤 버튼 보이기!
gsap.to(toTopEl, .2, {
x: 0
});
} else {
// 상단으로 스크롤 버튼 숨기기!
gsap.to(toTopEl, .2, {
x: 100
});
}
}, 300)); // 300 ms라는 뜻, 스크롤을 굴려도 0.3초마다 실행되게!
// _.throttle(함수() {}, 시간)
// 상단으로 스크롤 버튼을 클릭하면,
toTopEl.addEventListener('click', function () {
// 페이지 위치를 최상단으로 부드럽게(0.7초 동안) 이동.
gsap.to(window, .7, {
scrollTo: 0
})
});
사이트 구현은 모두 끝났다!! 이제 node.js로 가서 모듈 일치, 서버 구현 등 백엔드 지식을 쌓아보자!