4주차 주요 내용은 배웠던 기능들 사용해서 스타벅스 클론 페이지를 만들어보면서 HTML, CSS, JS 기능들 구현을 해보는 것이었다.

배운 것에 비해 생각보다 구현이 그럴듯한 것에 놀랐고, 객체 하나하나를 유심히 관찰해봐야겠다는 생각도 들었다. 물론 전체 사이트가 돌아가도록 페이지 라우팅이든 링크등이 들어가 있는 것은 아니지만 한 주 동안 만들어보면서 알게된 기능들을 기록해놓고자 한다.

페이지 구현 기능

1. 프로젝트 시작

  • 폴더 만들고 'index.html' 만들기
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" 
          content="width=device-width, initial-scale=1.0">
    <title>New Project</title>
</head>
<body>
    
</body>
</html>
  • 추가 설명

    @ 문자 인코딩(Character Encoding) 설정
    - 문자 인코딩 되는 방식을 설정한다.

@ 뷰포트(Viewport) 렌더링 방식 설정
- 웹페이지가 화면(Viewport)에 표현되는 방식을 설정함
- 모바일 환경(톡, sns) 등에서 자주 보임


  • favicon.ico / favicon.png

    • root폴더에 favicon.ico 또는 favicon.png를 넣으면 자동으로 타이틀 옆에 아이콘이 찍힌다.
    • ico가 해상도가 좋지않으면 링크 구문을 추가해 화질 더 나은 png파일로 교체 가능.
      icon만드는 site
      <head>
      	...
      	<link rel="icon" href="./favicon.png" />
      </head>

  • 브라우저는 자체적으로 CSS 셋팅값을 가지고 있다.

    • 브라우저마다 조금씩 셋팅이 달라 사이트의 통일감이 없을 수 있다.
    • 이를 방지하기 위해 CSS reset를 넣어놓고 진행하는 것이 좋다.
      <head>
      	...
      	<link rel="stylesheet" 
                href="https://cdn.jsdelivr.net/npm/reset-css@5.0.1/reset.min.css" />
      </head>
    • 이 후 CSS 스타일을 관리해줄 파일 지정
      ( root폴더 안 css폴더 만들고 'main.css' 생성 )
      <head>
      	...
      	<link rel="stylesheet" href="./css/main.css" />
      </head>

2. 오픈 그래프

웹페이지가 소셜 미디어(페이스북 등)로 공유될 때 우선적으로 활용되는 정보를 지정합니다.

오픈그래프 기능 링크

  • 트위터 카드(Twitter Cards)
    웹페이지가 소셜 미디어(트위터)로 공유될 때 우선적으로 활용되는 정보를 지정함

@ 용어 Check
SEO (검색 엔진 최적화, Search Engine Optimization)란,
구글이나 제이버 등에 자신의 웹사이트 / 페이지를 노출할 수 있도록 정보를 최적화 하는 작업을 말함.

3. Google Fonts

웹 브라우저마다 폰트 서체가 다를 수 있다. 크로스 브라우징 을 위해 따로 지정 필요

  • 나눔 고딕으로 지정해보자.
  • 폰트가 생각보다 용량이 많으므로 폰트지정을 남발하지 않도록 하자.
    // Google Fonts에서 고른 폰트 파일을 가져오기
    <head>
    	...
    	 <link rel="preconnect"
               href="https://fonts.gstatic.com" />
         <link href="https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700&display=swap" 
               rel="stylesheet" />
    </head>
  • 페이지에 폰트를 적용(CSS 상속)
    /* main.css에 넣기 */
    body {
      font-family: 'Nanum Gothic', sans-serif;
    }
  • 실제 적용되었는지 확인(dev_tool F12)
  • 폰트 저작권 주의 필요 오픈라이센스

4. Google Material Icons

구글 제공하는 무료 아이콘 : Google Material Icons

시작해보기 문서 Check

  • 디자인 시안이 존재하나 매번 디자이너에게 요청할 수 없으며, 간단히 제공하는 아이콘을 코드를 통해 사용 가능하다.

    // Google Material Icons 활용위해 붙여넣기 진행
    <head>
    	...
    	 <link rel="stylesheet" 
               href="https://fonts.googleapis.com/icon?family=Material+Icons" />
    </head>
    // 로그인 아이콘 선택해보자면?

    // body, 필요한 곳에 넣어주면 사용가능하다.
    <body>
    	...
    	 <span class="material-icons">login</span>
    </body>

5. 헤더와 드롭다운 메뉴

  • body > header 태그 넣기
    <body>
    	...
       <!-- HEADER -->
    	 <header></header>
    </body>

로고 삽입 구조

<header>
<div class="inner">
  <a href="/" class="logo"> // href="/" === href="도메인/index.html" 
    <img src="./images/logo.png" alt="이미지안뜰경우 설명부분" />
  </a>
</header>
/* CSS HEADER 부분 */

header {
}

header > .inner {
width: 1100px;       // 가로 길이 주고,
margin: 0, auto;     // 위아래 0, 좌우 auto 주면, 가운데 정렬 된다.
}

header .logo {
}
  • img는 인라인 요소이며, 일반적으로 height, width, margin 값을 가질 수 없다.

    • 인라인 요소는 글씨 취급을 위한 요소 였기 때문에 baseline 아래쪽에 공간을 가질 수 있는 상태이다.
      /* CSS COMMON 부분 */
      img {
        diplay: block;        // 디폴값인 인라인이 아닌 블록으로 취급하겠다 명시
                              //  baseline 밑 공간이 사라지게 된다
      }
  • header 높이가 로고보다 클 경우 빈 공간이 생기고, 수직 가운데 정렬 의 필요성이 생긴다.

    /* CSS HEADER 부분 */
    header {
    }
    
    header > .inner {
      height: 120px;      // 1. 높이가 주어져 있어, 아래에 공간이 생겨있을 때,       
      margin: 0, auto;   
      
      // 3. position 값이 없었으므로
      position: relative; // 포지션이 없을 경우 영향을 끼치지 않게 포지션 명명하는 것.
    }
    
    header .logo {
      position: absolute;  // 2. 부모요소를 기준잡아 위치를 설정 필요
                           //    중요 : 부모요소에 position 명명되어있어야만 작동!
    }

@ 연습해보기(배치)

/* CSS*/
.container {
  width: 400px;
  height: 250px;
  background-color: royalblue;
  position: relative;  // 3. 부모요소 보니 포지션 없어 문제 발생
}                      // 동작하게 하려면 position: relative 꼭 넣기
.item {
  background-color: orange; 
  
  width: 100px;
  height: 1000px;  // 5. 이유는 높이가 정확히 얼마인지 컴터가 인지해야 정상 작동 가능
                   //    있는지 꼭 확인하자.
  
  position: absolute;  // 1. 부모요소 기준 설정 선언
  
  top: 0;           // 2. 가운데 정렬을 위해선 시작값 끝값 필요
  bottom: 0;       // 위 0지점, 아래 0지점을 기준으로 잡겠다는 명시
  
  margin: auto 0;  // 4. 위아래는 auto로 주면 가운데 정렬이 되어야한다. 
}

  • 배치는 포지션 선언 있을 때 움직이는 개념이다.
    • height, position absol, top, bottom, margin auto

  • 수평 가운데 정렬도 동일하다.
    .item {
     width: 100px;       // 4. 좌우 여백 계산을 위한 가로 너비 꼭 필요!!
     height: 1000px;  
     
     position: absolute;  // 1. 부모요소 기준 설정 선언
     
     left: 0;           // 2. 좌우 시작값 지정 필요
     right: 0;         
     
     margin: auto;  // 3. 하나로 적으면 좌우상하 다 오토 하겠단 뜻.
    }


서브 메뉴 구조

  • 서브메뉴 4개, 포커스되면 통합검색 튀어나오도록 계획

    서브 메뉴 구조

    // index.html 안에 요소 만들어 놓기
    <header>
       <div class="inner">
      
         <div class="sub-menu">
           <ul class="menu">
             <li>
               <a href="/signin">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" />
             <span class="material-icons">search</span>
           </div>
         </div>
         
       </div>
    </header>
    

    해당 태그들 요소별로 선택자로 명시

    // 정확한 범위로 명명하는 습관을 기르자.
    // 나중에 사용하지 않더라도 모두 추가해놓고 시작 하는 것이 구조인식에 유리하다, 
    
    header .sub-menu {
       position: absolute;   // 부모요소인 inner에 position 있어서 건들거 없음.
       top: 10px;
       right: 0;
       display: flex;
    }
     header .sub-menu ul.menu {
       font-family: Arial, sans-serif;   // 폰트를 Arial로 지정, 없으면 고딕계열 되는걸로 지정
       display: flex;      // 수직으로 쌓인 메뉴를 수평으로 펼쳐줌
    }
     header .sub-menu ul.menu li {
       position: relative;
    }
     
     header .sub-menu ul.menu li::before {  // 가상요소 선택자! (메뉴 구분자)
                                            // li요소 앞에 가상으로 만들어 넣는 용도
       content: "";        // 넣을 글씨 / 안넣으면 비워서라도 있어야함. 안쓰면 안만들어짐.
       /* display: block;  // 가상요소는 인라인 요소여서, block으로 바꿔줘야 조절 가능하나 position absol/fixed 는 자동으로 block 만들어주므로 생략해도 됨 */
       width: 1px;     // 구분자용이기때문에 아주 폭 좁으면 됨.
       height: 12px;   // 글씨 폰트만큼의 사이즈
       background-color: #e5e5e5;
       position: absolute;   // li가 부모요소인데 포지션값없으므로 위에 적어줄 것
    }
    
     header .sub-menu ul.menu li:first-child::before { // before 요소중 맨 앞만 지정 
       display: none;   // 맨앞 메뉴 앞 구분자는 필요없으므로 안보이게 처리
    }
     header .sub-menu ul.menu li a {
       font-size: 12px;
       padding: 11px 16px; // a는 인라인 요소여서 여백 안먹는다.
       display: block;     // 블록요소로 바꾸겠다 선언하면 해결
                           // 블록은 가로를 최대한 늘리려하는 점 기억!
       color: #656565;
       text-decoration : none; // 하이퍼링크 밑줄을 없애줌. 
    }                          // a 모두 필요없으므로 common부분으로 올려주는게 더 좋다.
    
     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 {
    }

    검색 틀 만들기

    /* 검색틀 부분만 뽑아보면 */
    
    header .sub-menu {         // '상단 글씨 메뉴들''인풋icon''서브메뉴'의 요소들
      display: flex;           //  위의 두 요소를 수평으로 붙여줌.  
    }
    ...
    
    header .sub-menu .search {
      position: relative;
      height: 34px;
    }
    header .sub-menu .search input {             // 검색 입력박스 설정값들
      width: 36px;
      height: inherit;
      padding: 4px 10px;
      border: 1px solid #ccc;
      box-sizing: border-box;
      border-radius: 5px;                 // 모서리 둥글게 깎기
      outline: none;                      // 파란색 outline 컨트롤 어려우므로 없애기
      background-color: #fff;             // 배경 흰색
      color: #777;                        // 검색 글씨 색깔(회색)
      font-size: 12px;
      transition: width .4s;              // 전환효과 시간 
    }
    header .sub-menu .search input:focus {            // 인풋이 포커스 되면..
      width: 190px;                                   // 길이가 36 -> 190 되는 효과
      border-color: #669900;                          // 테두리 선색
    }
    header .sub-menu .search .material-icons {
      height: 24px;               // 요소 높이값있어야 배치 여백 길이 결정이 가능해진다.
      position: absolute;         // 부모요소 기준 삼기
      top: 0;                     // 시작값 끝값 필요
      bottom: 0;
      right: 5px;                 // 오른쪽으로 부터 5px 위치
      margin: auto;               // 수직 가운데 배치 진행
      transition: .4s;            // 전환 focused 되었을때 전환될 용도
    }
    header .sub-menu .search.focused .material-icons { // focused 넣었다 뺏다..
      opacity: 0;      // 안보이게 하기
    }

    JS 사용하기

    // html
    <head>
    <script defer src="./js/main.js"></script> // 스크립트 지정해올 곳 지정 
    </head>                                    // defer : html 코드가 끝나면 js 실행되도록
    // main.js
    const searchEl = document.querySelector('.search'); // html전체에서 search 클래스 찾기
    const searchInputEl = searchEl.querySelector('input'); // 이미 찾은거에서 input 찾기
    
    searchEl.addEventListener('click', function () {
      searchInputEl.focus(); // input 요소에 포커스 하라는 뜻
    });
    
    searchInputEl.addEventListener('focus', function () {
      searchEl.classList.add('focused'); //input에 focus가 되면 클래스에 focused를 추가해라
      searchInputEl.setAttribute('placeholder','통합검색');
      // 할당용도 setAttribute('속성이름', '넣을 내용' )
    });
    
    searchInputEl.addEventListener('blur', function () {
      searchEl.classList.remove('focused'); 
      searchInputEl.setAttribute('placeholder','');
    });

메인 메뉴 구조

  • 메뉴와 드롭다운 메뉴 만들기 연습

    메인메뉴 기본 골자

// index.html_submenu 밑에 추가
<ul class="main-menu">
  <li class="item">
    <div class="item__name">COFFEE</div>
    <div class="item__contents">
    </div>
  </li>
  <li class="item">
    <div class="item__name">MENU</div>
    <div class="item__contents">
    </div>
  </li>
  <li class="item">
    <div class="item__name">STORE</div>
    <div class="item__contents">
    </div>
  </li>
    <li class="item">
    <div class="item__name">RESPONSIBILITY</div>
    <div class="item__contents">
    </div>
  </li>
  <li class="item">
    <div class="item__name">MY STARBUCKS REWARDS</div>
    <div class="item__contents">
    </div>
  </li>
  <li class="item">
    <div class="item__name">WHAT'S NEW</div>
    <div class="item__contents">
    </div>
  </li>
</ul>

css

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 {   // item부분에 마우스를 올리면..(hover)
  background-color: #2C2A29;
  color: #669900;   // 글자 컬러
  border-radius: 6px 6px 0 0;  // 요소 둥글게 깎기 - 좌상 우상 우하 좌하
}

위의 구조잡은 html에 추가내용 입력

// index.html_submenu 밑에 추가
<ul class="main-menu">
  <li class="item">
    <div class="item__name">COFFEE</div>
    <div class="item__contents">
      <div class="contents__menu">
      <div class="contents__texture">
    </div>
  </li>
  <li class="item">
    <div class="item__name">MENU</div>
    <div class="item__contents">
      <div class="contents__menu">
      <div class="contents__texture">
    </div>
  </li>
  <li class="item">
    <div class="item__name">STORE</div>
    <div class="item__contents">
      <div class="contents__menu">
      <div class="contents__texture">
    </div>
  </li>
    <li class="item">
    <div class="item__name">RESPONSIBILITY</div>
    <div class="item__contents">
      <div class="contents__menu">
      <div class="contents__texture">
    </div>
  </li>
  <li class="item">
    <div class="item__name">MY STARBUCKS REWARDS</div>
    <div class="item__contents">
      <div class="contents__menu">
      <div class="contents__texture">
    </div>
  </li>
  <li class="item">
    <div class="item__name">WHAT'S NEW</div>
    <div class="item__contents">
      <div class="contents__menu">
      <div class="contents__texture">
    </div>
  </li>
</ul>

css내용 연장

header .main-menu .item .item__contents {
  width: 100%;
  position: fixed;  // 뷰포트를 기준으로 위치시키겠다_좌우 쫙 퍼지게 해야하므로..
  left: 0;     // top이나 bottom 속성을 사용하지 않아 수직 위치 없으면 요소 원위치를 그대로 사용
  display: none;   // 기본 화면에서는 지워져 있도록! 
}
header .main-menu .item:hover .item__contents {   // item의 마우스를 올리면
  display: block;  //display 속성을 block으로 만들기 
}
header .main-menu .item .item__contents .contents__menu {
  background-color: red;  // 위치 확인용
  height: 200px;
}
header .main-menu .item .item__contents .contents__texture {
  background-color: orange;  
  height: 100px;
}

한 메뉴만 완성해서 나머진 반복

      <ul class="main-menu">
        <li class="item">
          <div class="item__name">COFFEE</div>
          <div class="item__contents">
            <div class="contents__menu">
              <ul class="inner">  // div였던 inner를 ul 로 바꾸고 하부item 넣을 수 있다.
                <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>
      </ul>

css 요소 마무리

header .main-menu .item .item__contents .contents__menu {
  background-color: #2C2A29;
}
header .main-menu .item .item__contents .contents__menu > ul {
  padding: 20px 0;
  display: flex;
}
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: 900;
}
header .main-menu .item .item__contents .contents__texture p {
  color: #64a70b;
  margin: 4px 0 14px;
}

BEM (Block Element Modifier) - HTML 클래스 속성의 작명법
요소__일부분 : Underscore(Lodash) 기호로 요소의 일부분을 표시
요소--상태 : Hyphen(Dash) 기호로 요소의 상태를 표시


Badges 제작

	<div class = "inner">
  	...
	</div>
    <!--BADGES-->
    <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>

ㄴ 만든 요소에 css 씌우기

header .badges {
  position: absolute;  /* header가 부모고 포지션있는지 확인-> 없으므로 position: relative; 기입 */
  top: 132px;    // 위에서 132 지점 
  right: 12px;   // 오른쪽 12만큼 이동한 지점
}
header .badges .badge {
  border-radius: 10px;   // 모서리 깎기
  overflow: hidden;      // 이미지가 넘치지 않도록 흐른 값 숨기기
  margin-bottom: 12px;   // 아랫쪽 바깥여백 12
  box-shadow: 4px 4px 10px rgba(0,0,0,.15);    // x, y, blur,(0,0,0, 투명도)
  cursor: pointer;       // 마우스올리면 포인터 모양으로 커서 바꾸기       
}

현재는 스크롤 올리면 뱃지가 딸려올라가버린다.

position : fixed, absolute 에서는 가로가 최소한으로 줄어들어 버린다.
width: 100% 를 추가해줘야 원하는 대로 나온다.
뱃지 고정을 위해 position:fixed 로 바꿔주고, width: 100% 추가해준다.

header {
  width: 100%;
  position: fixed;
  background-color: #F6F5F0;
  border-bottom: 1px solid #c8c8c8;
  top: 0;
}

어느 수준이상 내려가면 뱃지가 사라지게 하고 싶다.
이는 js를 통해 구현 가능하다.

// index.html 헤더에 기입, 불러오기
 <!--Lodash-->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" 
          integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" 
          crossorigin="anonymous"></script>
// 페이지 스크롤에 영향을 받는 요소들을 검색!
const badgeEl = document.querySelector('header .badges')
// 페이지에 스크롤 이벤트를 추가!
// 스크롤할때마다 너무 많이 실행되게 되며 조절 필요(throttle, 일부러 부하를 줌)<- Lodash 함수
window.addEventListener('scroll', _.throttle(function () {
  if (window.scrollY > 500) {         // 페이지 스크롤 위치가 500px이 넘으면.
    badgeEl.style.display = 'none'
    }
  } else {                            // 페이지 스크롤 위치가 500px이 넘지 않으면.
    badgeEl.style.display = 'block'            // Badge 요소 보이기
  }
}, 300))  // 밀리세컨드, 0.3초 단위로 부하를 주라는 것  

gsap

gsap.to(애니메이션요소, 지속시간, 옵션);

// 페이지 스크롤에 영향을 받는 요소들을 검색!
const badgeEl = document.querySelector('header .badges')
// 페이지에 스크롤 이벤트를 추가!
// 스크롤할때마다 너무 많이 실행되게 되며 조절 필요(throttle, 일부러 부하를 줌)<- Lodash 함수
window.addEventListener('scroll', _.throttle(function () {
  if (window.scrollY > 500) {       // 페이지 스크롤 위치가 500px이 넘으면.
    gsap.to(badgeEl, .6, {          // Badge 요소 숨기기!
      opacity: 0,                   // 0으로 점점 서서히 사라지낟. 0.6초에 이어 사용
      display: 'none'               // 실제로 없는 요소로 없애주는 역할
    }
  } else {                          // 페이지 스크롤 위치가 500px이 넘지 않으면.
    gsap.to(badgeEl, .6, {          
      opacity: 1,
      display: 'block'              // Badge 요소 보이기!
    })
  }
}, 300));  // 밀리세컨드, 0.3초 단위로 부하를 주라는 것  

6. 순차적 애니메이션

뱃지까지를 header로 치고, 그이후부터의 구조는 section 들로 구분

  </header>

  <!--VISUAL-->
  <section class="visual">     // 의미적으로 구획을 나눈다는 것을 의미한다. 별 역할을 없다.
    <div class="inner">

      <div class="title fade-in">            // 대체 text
        <img src="./images/visual_title.png" alt="STARBUCKS DELIGHTFUL START TO THE YEARS" />
        <a href="javascript:void(0)" class="btn btn--brown">자세히 보기</a>
      </div>     // 링크에 빈 링크 넣는 방법!
      <div class="fade-in">  // 같이 움직이게 하기 위해서 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" />
      </div>
      <div class="fade-in">   //묶어 준 것을 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">  // 얘는 하나이지만 얘도 사라졌다 보여지게 해야하므로 fade-in 넣어준다.
        <img src="./images/visual_spoon.png" alt="Spoon" class="spoon" />
      </div>

    </div>
  </section>

css 채우기

/*VISUAL*/
.visual {
  margin-top: 120px;   // header 내 inner 으 높이 값
  background-image: url("../images/visual_bg.jpg");
  background-position: center;   // 정가운데 하나만 넣겠다.
}
.visual .inner {
  height: 646px;   // 배경부분에 맞춰서 내려주는 역할
}
.visual .title {
  position: absolute;
  top: 88px;
  left: -10px;
}
.visual .title .btn {
  position: absolute;
  top: 259px;
  left: 173px;
}
.visual .cup1.image {
  position: absolute;
  bottom: 0;
  right: -47px;
}
.visual .cup1.text {
  position: absolute;
  top: 38px;
  right: 171px;
}
.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;
}
.visual .fade-in {     // fade-in 들어가 있는 클래스 기본적으로 안보이게 하고 시작
  opacity: 0;
}

버튼 모양들 만들어 놓기

/*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;
}
.btn:hover {
  background-color: #333;
  color: #FFF;
}
.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;
}

시간차로 순차적으로 표현

// 뱃지 이후 부분에다 기입
const fadeEls = document.querySelectorAll('.visual .fade-in');
fadeEls.forEach(function (fadeEl, index) {
  gsap.to(fadeEl, 1, {    //gsap.to(요소, 지속시간(초), 옵션);
    delay: (index + 1) * 0.7,    // 0.7초씩 차이나도록 딜레이를 줌 0.7, 1.4, 2.1, 2.8
    opacity: 1   // 보이게 하기
  });     // 반복되는 코드를 만들어야 자동화시킬 수 있다.
});    

7. 요소 슬라이드

공지사항

  // main.html에 공지부분 구조잡기

  </section>
  <!--NOTICE-->
  <section class="notice">
    <!--NOTICE LINE-->
    <div class="notice-line">
      <div class="bg-left"></div>
      <div class="bg-right"></div>
      <div class="inner"></div>
    </div>
  </section>  
/*NOTICE*/
.notice {

}
.notice .notice-line {

}
.notice .notice-line .bg-left {
  posiion: absolute;    // 구조적 부모인 노티스라인에 position 넣어줄것.
  top: 0:
  left: 0;
  width: 50%;
  height: 100%;
  background-color: #333;
}
.notice .notice-line .bg-right {
  posiion: absolute;
  top: 0:
  right: 0;
  width: 50%;
  height: 100%;
  background-color: #f6f5ef;
}
.notice .notice-line .inner {
  height: 200px;   //잠깐 키워놓은 것. // inner만 제어해주면 나머지가 알아서 맞춰진다.
}

html에 이어서 만들어 주기

  </section>
  <!--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"></div>
        <div class="inner__right"></div>
      </div>
    </div>
  </section>  

css 이어서

/*NOTICE*/
...
.notice .notice-line .inner {
  height: 62px;
  display: flex;  // 자식요소들이 수평으로 맞춰짐
}
.notice .notice-line .inner__left {
  width: 60%;  // 내부 요소이용해 검은부분이 좀 더 생기도록 제작	
  height: 100%;   
  background-color: #333;
}
.notice .notice-line .inner__right {
  width: 40%;	
  height: 100%; 
}

내부요소 구조 코딩

        <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">
            <span class="material-icons">add_circle</span>
          </a>
        </div>

        <div class="inner__right">
          <h2>스타벅스 프로모션</h2>
          <div class="toggle-promotion open">
            <div class="material-icons">upload</div>
          </div>
        </div>

css 내부요소들 내용 채우기

.notice .notice-line .inner__left {
  width: 60%;  
  height: 100%;   
  background-color: #333;
  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 {
  height: 62px;  // 줄어들어 버린 공간은 높이를 주어줌에 따라 다시 생긴다.
  flex-grow: 1;  // 원래는 최소한으로 쪼그라들어 안보이는데 이렇게 해주면 최대한으로 늘어난다
}
.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;
}

ㄴ기본적인 레이아웃은 마무리 되었으며, 컨테이너부분에 실제 공지사항 돌도록 만들어보겠다

수직 슬라이드(Swiperjs)

  // main.js 부분 위에 의존성 불러오기, css 작업 되어있기때문에 css도 필요하다.
  <!--Swiper-->
  <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>
-------------------------------------------------------------------------구조 한번 더 확인 -----------------------------------------------------------------------------


// main.js 안에 기입

// new Swiper(선택자, 옵션)
new Swiper ('.notice-line .swiper-container', {                  // 생성자 만들기
  direction: 'vertical',      // 이것만 넣어도 동작(수직슬라이드)! 수동으로 올라간다.
  autoplay: true,             // 자동 재생 유무
  loop: true,                 // 반복 재생 여부
});  

css 요소를 추가하여 스타일 정리하기

// 이전 작업해놨던것에 이어서 추가 기입
.notice .notice-line .inner__left .swiper-container {
  height: 62px;  
  flex-grow: 1;  
}
.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;     
}

프로모션 영역 (가로 슬라이드)

// index.html
// 공지사항 부분 div 이후 형제요소로 div class="promotion" 생성(.notice 섹션 안에 있는 것임)
    <!--PROMOTION-->
    <div class="promotion">

      <div class="swiper-container">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <img src="./images/promotion_slide1.jpg"   
                 alt="2021 뉴이어, 스타벅스와 함께 즐겁고 활기차게 시작하세요!" />  // 이미지와 대체text 기입
            <a href="javascript:void(0)" class="btn">자세히 보기</a>  // 버튼 넣기
          </div>         // 5가지 프로모션 카드 만들기 (동일내용 x5)                          
        </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>

스타일 제작

/*PROMOTION*/
.notice .promotion {
  /*width: auto;*/
  height: 693px;
  background-color: #f6f5ef;
  position: relative;
  overflow: hidden;
  transition: height .4s;
}
.notice .promotion.hide {
  height: 0;
}
.notice .promotion .swiper-container {
  /* 819px 슬라이드 3장와 그 사이 여백 10px씩 = 2477px */     /* ex) 100% - 50px 같은것도 됨 */
  width: calc(819px * 3 + 20px);    /* 수학 계산 필요할 경우 함수, css 계산에서 유용*/
  height: 553px;   /* 이미지 크기에 맞게 */
  position: absolute; /* 부모요소 기준 배치 -> 프로모션 부분에 relative 지정 */
  top: 40px;    /* 위에서 부터 40px 만큼 조금 내리기 */
  left: 50%;   /* 컨테이너 부분을 일단 절반까지 밀어 놓는다. */
  margin-left: calc((819px * 3 + 20px) / -2);     /* 마진 레프트: - (가로의 절반) <- 이렇게 가운데 정렬 시킨다.*/
}
  /* right: 50%  + margin-right: - (컨테이너의 가로값의 절반)  으로 작업도 가능하다. 이래야 요소가 정렬이 잘된다.*/
  
.notice .promotion .swiper-slide {
  position: relative;  /* 버튼 배치 때문에 필요 */
  opacity: .5;     /* 반투명해지도록 작업 */
  transition: opacity 1s;    /*자연스러운 전환효과 추가*/
}
.notice .promotion .swiper-slide-active {
  opacity: 1;       /*가운데 보이는 active 부분만 불투명하게 잘 보이게 됨*/
}
.notice .promotion .swiper-slide .btn {   /* 버튼 정의 */
  /*width: 130px;*/
  position: absolute;  /* 부모상 요소에 포지션 추가 필요  swiper-slide 에 relative 기입 */
  bottom: 0;   /* 버튼은 아래쪽으로 붙이길 원함 */
  left: 0;  /* 좌우 끝점 잡기 */
  right: 0; /* 좌우 끝점 잡기 */
  margin: auto;  /* 마진 오토로 자동으로 정렬되게 하기(가운데 배치) -> 요소 가로 너비 필요 common에 이미 있어 필요 없음*/
}
.notice .promotion .swiper-pagination {   /* 페이지 요소 00000  가 이동된다. */
  bottom: 40px;
  left: 0;
  right: 0;         /* swiper css 에 기본 내용 이미 잡혀있다. f12로 확인해보는 것 필요*/
  z-index: 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; /* 보기 안좋은 아웃라인 없애기 */
}
.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"); /* 배경이미지 바꿔주기 */
}
.notice .promotion .swiper-prev,     /* 다중 선택자 */
.notice .promotion .swiper-next {
  width: 42px;    /* 가로 사이즈 */
  height: 42px;   /* 세로 사이즈 */
  outline: none;  /* 지저분한 기본 아웃라인 제거 */
  border: 2px solid #333; 
  border-radius: 50%; /* 둥글게 깎기 */
  position: absolute;
  
  /* Swiper Container 높이의 절반만큼 끌어올림 */
  /* 버튼 높이의 절반만큼 추가로 끌어올림 */
  top: 300px;
  z-index: 1;
  cursor: pointer;
  display: flex;  /* 넣은 아이콘  수평 정렬 가능하게끔.. */
  justify-content: center; /* 수평 가운데 */
  align-items: center;     /* 수직 가운데 */
  transition: .4s;       /* 전환효과 0.4초 */
}
/* 분별되어야 하는 부분은 아래에 따로 적어주면 된다 */
.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;  /* 색 흰색으로 */
}

js 기능 삽입


new Swiper('.promotion .swiper-container', {
  // direction: 'horizontal', // 수평 슬라이드 : swiper direction의 디폴트값이므로 쓸필요X
  autoplay: { // 자동 재생 여부 -> { }로 입력하면 안에 속성 넣을 수 있다.
    delay: 5000 // 5초마다 슬라이드 바뀜
  },
  loop: true, // 반복 재생 여부  // 이거 안넣으면 양옆이 비어있다. 반복적으로 넣기위해 loop필요
  slidesPerView: 3, // 한 번에 보여줄 슬라이드 개수  , 기본값은 1임
  spaceBetween: 10, // 슬라이드 사이 여백   10px 간격 생김
  centeredSlides: true, // 1번 슬라이드가 가운데 보이기 (처음 보일 슬라이드가 가운데부터!)
  pagination: {         // 페이지 번호 사용 여부
    el: '.promotion .swiper-pagination', // 페이지 번호 요소 선택자  (이 요소를 페이지 번호로 사용하겠다)
    clickable: true                // 사용자의 페이지 번호 요소 제어 가능 여부 (실제 클릭 제어 가능 유무)
  },
  navigation: {         // 슬라이드 이전/다음 버튼 사용 여부
    prevEl: '.promotion .swiper-prev',      // 이전 버튼 선택자 명시
    nextEl: '.promotion .swiper-next'       // 다음 버튼 선택자 명시
  }
})
  • 가운데에서 사용자에게 보여질 class는 swiper-slide-active 가 추가되어 있다. 잘 쓰니 기억!!

슬라이드 영역 토글

// index.html
// notice line 안에 오른쪽 부분에
        <div class="inner__right">
          <h2>스타벅스 프로모션</h2>
          <div class="toggle-promotion open">
            <div class="material-icons">upload</div>
          </div>
        </div>
// 토글부분이 있었다. 버튼누르면 아래 프로모션이 접히도록 해보자
  • js 부분
/**
 * Promotion 슬라이드 토글 기능
 */
// 슬라이드 영역 요소 검색!
const promotionEl = document.querySelector('.promotion')
// 슬라이드 영역를 토글하는 버튼 검색!
const promotionToggleBtn = document.querySelector('.toggle-promotion')
// 슬라이드 영역 숨김 여부 기본값!
let isHidePromotion = false
// 토글 버튼을 클릭하면,
promotionToggleBtn.addEventListener('click', function () {  // 클릭하면 함수 실행
  // 슬라이드 영역 숨김 여부를 반댓값으로 할당! (상태를 뒤집는 용도)
  isHidePromotion = !isHidePromotion  
  // 요소를 숨겨야 하면,
  if (isHidePromotion) {   // 처음에 false 였는데 뒤집었으므로 true 된상태이며, if 조건 성립
    promotionEl.classList.add('hide')  // class에 hide 추가
  // 요소가 보여야 하면,
  } else {  // 한번더 누르면 false가 될것이므로 else 실행 됨.
    promotionEl.classList.remove('hide')  // hide 가 사라진다. <- css 스타일로 조절가능  
  }
})

스타일로 조정


.notice .promotion {
  /*width: auto;*/
  height: 693px;
  background-color: #f6f5ef;
  position: relative;
  
  transition: height .4s;  /* 전환, 부드럽게 줄어들도록 효과 */
  overflow: hidden;        /* 넘쳐지는 부분 잘라버리기 */
}

.notice .promotion.hide {
  height: 0;   /* 높이가 없어지면 말려 올라가는 효과 */
}

8. 유튜브 영상 배경

리워즈 작업

// index.html
// notice 뒤에 기입
  <!--REWARDS-->
  <section class="rewards">
    <div class="bg-left"></div>
    <div class="bg-right"></div>
    <div class="inner"></div>
  </section>

css 설정

/*REWARDS*/
.rewards {
  position: relative;
}
.rewards .bg-left {
  width: 50%;    /* 그림 왼쪽에 동일 색으로 채우기(반인 이유는 나머지 반은 그림이 채워주는 상태) */
  height: 100%;  /* 눂이는 다 채우기 */
  background-color: #272727; /* 색은 그림색과 동일하게 */
  position: absolute;   /* 부모요소 확인 -> 리워드에 relative 넣는다. */
  top: 0; 
  left: 0;
}
.rewards .bg-right {    /* left와 동일 */
  width: 50%;
  height: 100%;
  background-color: #d5c798;
  position: absolute;
  top: 0;
  right: 0;
}
.rewards .inner {
  background-image: url("../images/rewards.jpg");   /* 배경 이미지 출력 */
  height: 241px;
}

남은 버튼 요소 넣기

// 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>

css 버튼 부분 설정

/* 버튼그룹만들어 조절 */
.rewards .btn-group {
  position: absolute; /* 부모요소는 inner이며 전역css에 추가되어있으므로 할필요는 없다. */
  right: 0;        /* 우측 붙여서 놓기 */
  bottom: 24px;    /* 바닥 24px 지점에 놓기*/
  width: 250px;    /* 그룹 가로너비 250 잡고 */
  display: flex;   /* 요소 가로 정렬되도록 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;  /* 최대한 너비로 늘어나게 됨. */
}

youtube 영상배경

// html 요소 구조
<!--YOUTUBE VIDEO-->
  <section class="youtube">
    <div class="youtube__area">
      <div id="player"></div>
    </div>
    <div class="youtube__cover"></div>
  </section>

css 조절

/*YOUTUBE VIDEO*/
.youtube {
  position: relative; 
  height: 700px;   /* 최대 높이 부분 */
  background-color: #333;   /* 어두운 회색으로 출력 */
  overflow: hidden; /* 넘치는 부분 잘린다. */
}
.youtube .youtube__area {
  width: 1920px;   /* FHD 1920x1080 */
  position: absolute;

  left: 50%;  
  margin-left: calc(1920px / -2);  /* 가운데 두는 스킬 위에 했었다. */ 
  
  /* 16: 9비율 */
  top: 50%;  
  margin-top: calc(1920px * 9 / 16 / -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);  /* 30% 불투명도 가진 검정색 넣기 - 어두워진다 */
  background-image: url("../images/video_cover_pattern.png"); /* 배경 사선 패턴 넣기 */
}

새로운 js 파일 생성

// 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 onYouTubePlayerAPIReady() {
  // <div id="player"></div> 아이디 선택자 # 쓰면 안됨.
  new YT.Player('player', {
    videoId: 'An6LvWQuj_8', // 최초 재생할 유튜브 영상 ID - 소스코드 복사해서 id값 추출
    playerVars: {
      autoplay: true, // 자동 재생 유무
      loop: true, // 반복 재생 유무 true 인경우 id 목록(플레이리스트) 할당해줘야함!!!!
      playlist: 'An6LvWQuj_8' // 반복 재생할 유튜브 영상 ID 목록
    },
    events: {
      // 영상이 준비되었을 때, 실행 -> 상황을 event 라는 매개변수로 받아 사용
      onReady: function (event) {  
        event.target.mute() // event 안에는 target이라는 속성이 있으며, mute 명령어로 음소거 처리 실행!
      }
    }
  })
}
// index.html 안

// main.js 선언 된 코드 위에 
  <script defer src="./js/youtube.js"></script>   // defer : html 다 불러오고, 실행되게 함.

css 위 내용에 추가

#player {    /* id="player" */
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

영상위에 둥둥떠다니는 반복 애니메이션

// 유튜브 비디오 부분 안에 inner 부분 만들기
<!--YOUTUBE VIDEO-->
  <section class="youtube">
    <div class="youtube__area">
      <div id="player"></div>
    </div>
    <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>
  </section>
/* css 추가 */
.youtube .inner {
  height: inherit;
}
.youtube .floating1 {
  position: absolute;
  top: 50px;
  left: 0;
}
.youtube .floating2 {
  position: absolute;
  top: 350px;
  left: 150px;
}
.youtube .floating3 {
  position: absolute;
  bottom: -200px;
  right: 0;            
  // 이부분이 반이 잘리게 되고 overflow hidden 때문이고, 지운 뒤 아래 요소에 붙일 예정
}

js 애니메이션 효과 주기

/**
 * 부유하는 요소 관리
 */

// 범위 랜덤 함수(소수점 2자리까지) 만들어 놓고 사용
function random(min, max) {
  // `.toFixed()`를 통해 반환된 '문자 데이터'를,
  // `parseFloat()`을 통해 소수점을 가지는 '숫자 데이터'로 변환
  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), // 얼마나 늦게 애니메이션을 시작할 것인지 지연 시간을 설정.
      y: size, // `transform: translateY(수치);`와 같음. 수직으로 얼마나 움직일지 설정.
      repeat: -1, // 몇 번 반복하는지를 설정, `-1`은 무한 반복.
      yoyo: true, // 한번 재생된 애니메이션을 다시 뒤로 재생. 왓다갔다기능(둥둥 느낌)
      ease: Power1.easeInOut // Easing 함수 적용.
    }
  )
}
// 만들어놓은 함수 사용 
floatingObject('.floating1', 1, 15)
floatingObject('.floating2', .5, 15)
floatingObject('.floating3', 1.5, 20)

gsap.to() 사용법
GSAP Easing

9. 고정 이미지 배경

시즌 프로덕트 제작

// 유튜브 비디오 부분 밑에 섹션 추가

  <!--SEASON PRODUCT-->
  <section class="season-product scroll-spy"> 
  // scroll-spy 부분은 스크롤내리다 보이면 움직이는 그룹으로 지정
    <div class="inner">

      <img src="./images/floating3.png" alt="Icon" class="floating floating3" /> // 위에 있던 잘렸던 애니메이션 하나 옮겨오기(overflow hidden 없는 곳으로 온것임)
      <img src="./images/season_product_image.png" 
           alt="아이스 커피 블렌드" 
           class="product back-to-position to-right delay-0" /> 
           /* 스크롤매직(11.) 통한 애니매이션때 사용 */

      <div class="text-group">
        
        <img src="./images/season_product_text1.png" 
             alt="상쾌하게 여름을 반겨줄 시즌 원두 아이스 커피 블렌드" 
             class="title back-to-position to-left delay-1" />
             /* 스크롤매직(11.) 통한 애니매이션때 사용 */
        
        <img src="./images/season_product_text2.png" 
             alt="아프리카와 라틴 아메리카 커피의 브렌드로 시트러스함과 은은한 캐러멜 향을 동시에 느낄 수 있으며, 차갑게 즐길 때 풍미가 더욱 깊어지는 원두입니다." 
             class="description back-to-position to-left delay-2" />
             /* 스크롤매직(11.) 통한 애니매이션때 사용 */
        
        <div class="more back-to-position to-left delay-3">
          <a href="javascript:void(0)" class="btn">자세히 보기</a>
        </div>
        
      </div>

    </div>
  </section>

css 스타일

/*SEASON PRODUCT*/
.season-product {
  background-image: url("../images/season_product_bg.jpg");
}
.season-product .inner {
  height: 400px;
}
.season-product .floating3 {   /* 부모요소 바뀐것 확인 */
  position: absolute;  /* 부모요소 inner 이므로 이미 되어있음*/
  top: -200px;  /* 아까랑 위치 다름 주의 들어있는 부분이 다르기 때문(그냥 붙여넣으면 안됨) */
  right: 0;
}
.season-product .text-group {
  position: absolute;
  top: 110px;
  right: 100px;
}
.season-product .text-group .title {
  margin-bottom: 10px;   // 아래 여백 주기
}
.season-product .text-group .description {
  margin-bottom: 15px;   // 아래 여백 주기(사이사이 틈을 주는 효과)
}

리저브 커피 섹션 제작

// 위에 코드에 연결해서 
  <!--RESERVE COFFEE-->
  <section class="reserve-coffee scroll-spy"> 
  // scroll-spy 부분은 스크롤내리다 보이면 움직이는 그룹으로 지정
    <div class="inner">

      <img src="./images/reserve_logo.png" 
           alt="" 
           class="reserve-logo back-to-position to-right delay-0" />
           /* 스크롤매직(11.) 통한 애니매이션때 사용 */
      
      <div class="text-group">
        <img src="./images/reserve_text.png" 
             alt="" 
             class="description back-to-position to-right delay-1" />
             /* 스크롤매직(11.) 통한 애니매이션때 사용 */
        
        <div class="more back-to-position to-right delay-2">
                         /* 스크롤매직(11.) 통한 애니매이션때 사용 */
          <a href="javascript:void(0)" class="btn btn--gold">자세히 보기</a>  // 버튼이 잘안바뀌어서 골드로 바꿈
        </div>
      </div>
      <img src="./images/reserve_image.png" 
           alt="" 
           class="product back-to-position to-left delay-3" />
           /* 스크롤매직(11.) 통한 애니매이션때 사용 */
    </div>
  </section>

대응 css 부분

/*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-->
  <section class="pick-your-favorite scroll-spy">
    <div class="inner">

      <div class="text-group">
        
        <img src="./images/favorite_text1.png" 
             alt="PICK YOUR FAVORITE" 
             class="title back-to-position to-right delay-0" />
             /* 스크롤매직(11.) 통한 애니매이션때 사용 */
        
        <img src="./images/favorite_text2.png" 
             alt="다양한 메뉴를 스타벅스에서 즐겨보세요." 
             class="description back-to-position to-right delay-1" />
             /* 스크롤매직(11.) 통한 애니매이션때 사용 */
        
        <div class="more back-to-position to-right delay-2">
                         /* 스크롤매직(11.) 통한 애니매이션때 사용 */
          <a href="javascript:void(0)" class="btn btn--white">자세히 보기</a>
        </div>
        
      </div>

    </div>
  </section>

대응 css

/*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; /* 배경 이미지를 넓은 너비에 맞춰 출력될 것*/
}
.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;  /* 아래 여백 주기(사이 틈 주기) */
}

10. 3D 애니메이션

// html 요소 구조

  // 180도씩 앞뒤로 회전되는 3D 애니메이션 
  <!--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;  /* 원근법 거리 줘야 3D로 보임 */
}
.reserve-store .medal .front,
.reserve-store .medal .back {   /* 앞뒤 메달 공통요소  */
  width: inherit;    /* 334px */
  height: inherit;   /* 334px */
  position: absolute;  /* 메달들 같이 붙는다 */
  transition: 1s;  /* 자연스러운 회전 요소위해 */
  backface-visibility: hidden;  /* 뒤집어졌을때 화면에서 안보이게 하기 */
}
.reserve-store .medal .front {
  transform: rotateY(0deg);  /* 0도에서 출발하겠다고 명시 */
}
.reserve-store .medal:hover .front {
  transform: rotateY(180deg); /* 180도로 회전할 것 */
}
.reserve-store .medal .back {
  transform: rotateY(-180deg);
}
.reserve-store .medal:hover .back {
  transform: rotateY(0deg);  /* 마우스 올리면 적용 */
}
.reserve-store .medal .back .btn {
  position: absolute;
  top: 240px;
  left: 0;
  right: 0;
  margin: auto;  /* 가운데 배치 하고 싶으면 가로너비, 시작점left, 끝점right 필요하다 */
}

11. 스크롤 위치 계산 애니메이션

  • 화면에 보이면 애니메이션 처리 하도록 !!
// 리저브 스토어 아래 새 섹션 추가
  // 구조 잡기
  <!--FIND THE STORE-->
  <section class="find-store scroll-spy">  // 화면에 요소가 보이는지 판단해줄 라이브러리"scrollmagic"
  // scroll-spy 부분은 스크롤내리다 보이면 움직이는 그룹으로 지정  
    <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="picture picture1 back-to-position to-right delay-0" />
           /* 스크롤매직(11.) 통한 애니매이션때 사용 */
      
      <img src="./images/find_store_picture2.jpg" 
           alt=""
           class="picture picture2 back-to-position to-right delay-1" />
           /* 스크롤매직(11.) 통한 애니매이션때 사용 */
      
      <div class="text-group">
        
        <img src="./images/find_store_text1.png" 
             alt="스타벅스를 가까이에서 경험해보세요." 
             class="title back-to-position to-left delay-0" />
             /* 스크롤매직(11.) 통한 애니매이션때 사용 */
        
        <img src="./images/find_store_text2.png" 
             alt="고객님과 가장 가까이 있는 매장을 찾아보세요!" 
             class="description back-to-position to-left delay-1" />
             /* 스크롤매직(11.) 통한 애니매이션때 사용 */
        
        <div class="more back-to-position to-left delay-2">
          <a href="javascript:void(0)" class="btn">매장찾기</a>
        </div>
        
      </div>

    </div>
  </section>

대응 css

/*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;  /* 공통부분으로 1,2 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 라이브러리 가져오기
//main.js 선언 위에 놓자
  <!--ScrollMagic-->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.8/ScrollMagic.min.js"></script>
// main.js 에서 라이브러리 사용 및 요소 관리

/**
 * 요소가 화면에 보여짐 여부에 따른 요소 관리
 */
// 관리할 요소들 검색!
const spyEls = document.querySelectorAll('section.scroll-spy')
// 요소들 반복 처리!
spyEls.forEach(function (spyEl) {
  new ScrollMagic
    .Scene({ // 감시할 장면(Scene)을 추가
      triggerElement: spyEl, // 보여짐 여부를 감시할 요소를 지정
      triggerHook: .8 // 화면의 80% 지점에서 보여짐 여부 감시  (아래쪽에 가깝다. 위0, 아래1)
    })
    .setClassToggle(spyEl, 'show') // 요소가 화면에 보이면 show 클래스 추가 (토글 넣었다 뺏다 할 것)
    .addTo(new ScrollMagic.Controller()) // "컨트롤러"에 장면을 할당(필수!)
})
  • common css 로 show 부분 만들 것
/*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;            /* 전후상태 지연 시작 시간 줌 0s 는 필요없지만 명시(바로시작) */
}
.show .back-to-position.delay-1 {  /* 전후상태 지연 시작 시간 줌 0.3초 간격으로 늘릴것 */
  transition-delay: .3s;
}
.show .back-to-position.delay-2 {  /* 전후상태 지연 시작 시간 줌 0.6s */
  transition-delay: .6s;
}
.show .back-to-position.delay-3 {  /* 전후상태 지연 시작 시간 줌 0.9s 결국 순서대로 나오게 되는 효과 */
  transition-delay: .9s;
}

12. 다중요소 슬라이드

  • 다중이미지들 슬라이드 해보고자 한다
  • swiper 복습한다 생각하고 사용
// 새 새션 추가
  // 구조 요소 만들어 놓기
  <!--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>

js에 슬라이드 효과 넣기

// main.js 슬라이드 요소 있는 곳 아래에 이어서 기입

// 슬라이드 요소 관리에 같이 넣어놓는게 나중에 조절, 관리가 편하다
new Swiper('.awards .swiper-container', {
  // direction: 'horizontal', // 수평 슬라이드
  autoplay: true, // 자동 재생 여부
  loop: true, // 반복 재생 여부
  spaceBetween: 30, // 슬라이드 사이 여백
  slidesPerView: 5, // 한 번에 보여줄 슬라이드 개수 '5개 한번에 보이게 하겠다.'
  // slidesPerGroup: 5, // 한 번에 슬라이드 할 개수(전체 개수로 나뉘어야 함)
  navigation: { // 슬라이드 이전/다음 버튼 사용 여부
    prevEl: '.awards .swiper-prev', // 이전 버튼 선택자
    nextEl: '.awards .swiper-next' // 다음 버튼 선택자
  }
})
  • 실행은 되는데 배경도 없고 여백도 없어 미완성티가 팍팍난다.

css 스타일주기

/*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;  /* 불투명도 30% */
  cursor: pointer;
  display: flex;     /* 수평나열 가능하도록 */
  justify-content: center; /* 수평 가운데 */
  align-items: center;     /* 수직 가운데 */
  transition: .4s;     /* 전환 효과 부드럽게 0.4초에 거쳐서 */
}
.awards .swiper-prev {
  left: -100px;
}
.awards .swiper-next {
  right: -100px;
}
.awards .swiper-prev:hover,
.awards .swiper-next:hover {   /* 가상 선택자 : 마우스 올릴경우 공통 설정 */
  background-color: #fff;     /*  배경 흰색으로 */
  color: #333;                /* 글자 어두운 회색으로 */ 
}

13. 푸터

  • 가장 하단 부분 -> "Footer"
  <!--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">  // 현재 날짜에 맞춰서 바뀌도록 js 사용하여 코딩할거다
        &copy; <span class="this-year"></span> Starbucks Coffee Company. All Rights Reserved.
        <!--&copy; : 실제 동그라미c 가 나온다 , <div> == &lt; div &gt;   <- [html Entities]  -->
      </p>
      <img src="./images/starbucks_logo_only_text.png" alt="STAR BUCKS" class="logo" />

    </div>
  </footer>

대응 css

/*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 {   /* 가상요소 선택자 */
  content: "";  /*컨텐트 안써도 꼭 필요*/
  width: 3px;
  height: 3px;
  background-color: #555;  
  position: absolute;  /*fixed와 absolute 는 자동으로 block으로 바뀌며, 너비높이 지정가능*/
  top: 0;
  bottom: 0;
  right: -1px; 
  margin: auto;  /*수직 가운데 배치 */
}
footer .menu li:last-child::before {  /* 사이사이 점 부분으로 사용 */
  display: none;          /* li 테그 중 가장 마지막 요소, 안보이게 하겠다. */
}
footer .menu li a {
  display: 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;  /* 가운데 정렬 */
  margin-top: 12px;  /* 위쪽 바깥 여백 주기 */
}
footer .logo {
  /*좌우 가운데 정렬 가능한 이유는 img 요소는 width 안줘도 길이를 안다고 가정된다.*/
  margin: 30px auto 0; /* 상, 좌우(중), 하 */
}
  • 푸터까지 다 만들었기 때문에 body 부분 높이가 있다면 제거해줘라.

  • 날짜 넣기
 // main.js

/**
 * 올해가 몇 년도인지 계산
 */
const thisYear = document.querySelector('.this-year')
thisYear.textContent = new Date().getFullYear()
                           // javascript 생성자 함수 -> 날짜정보를 가지고 있음.

14. 페이지 상단으로 이동(ScrollTo)

// 맨 마지막 부분에 넣기
  <!--TO TOP BUTTON-->
  <div id="to-top">
    <div class="material-icons">arrow_upward</div>
  </div>

</body>
</html>
  • 뱃지 스크롤 효과 기억해보면 이해 쉽다.
/* main.css */

/*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;      /* 수직 가운데 */
}
// gsap 가져온 부분 아래에 추가  
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/ScrollToPlugin.min.js" 
        integrity="sha512-nTHzMQK7lwWt8nL4KF6DhwLHluv6dVq/hNnj2PBN0xMl2KaMm1PM02csx57mmToPAodHmPsipoERRNn4pG7f+Q==" 
        crossorigin="anonymous"></script>

js에 스크롤 요소 제어 넣기

// main.js

/**
 * 페이지 스크롤에 따른 요소 제어
 */
// 페이지 스크롤에 영향을 받는 요소들을 검색!
const badgeEl = document.querySelector('header .badges')
const toTopEl = document.querySelector('#to-top')      // 이 부분 추가
// 페이지에 스크롤 이벤트를 추가!
// 스크롤이 지나치게 자주 발생하는 것을 조절(throttle, 일부러 부하를 줌)
window.addEventListener('scroll', _.throttle(function () {
  // 페이지 스크롤 위치가 500px이 넘으면.
  if (window.scrollY > 500) {
    // Badge 요소 숨기기!
    gsap.to(badgeEl, .6, {
      opacity: 0,
      display: 'none'
    })
    
    // 상단으로 스크롤 버튼 보이기!  // 이 부분 추가
    gsap.to(toTopEl, .2, {
      x: 0
    })

  // 페이지 스크롤 위치가 500px이 넘지 않으면.
  } else {
    // Badge 요소 보이기!
    gsap.to(badgeEl, .6, {
      opacity: 1,
      display: 'block'
    })
    
    // 상단으로 스크롤 버튼 숨기기!  // 이 부분 추가
    gsap.to(toTopEl, .2, {
      x: 100
    })
  }
}, 300))


// 상단으로 스크롤 버튼을 클릭하면,
toTopEl.addEventListener('click', function () {
  // 페이지 위치를 최상단으로 부드럽게(0.7초 동안) 이동하고자 함
  gsap.to(window, .7, {    // 윈도우 객체 -> 출력하는 화면자체 (창)
    scrollTo: 0            // gsap.to(요소, 시간, 옵션)
  })
})
  • 최상단 이동이 잘 되는 것을 알 수 있다.

이것으로 클론페이지를 만들어 보았다. 웹사이트 만들어지는 원리를 조금이나마 알게된것 같다, 예전보다는 웹 페이지 해석이 가능해지지 않았을까 싶다.


출처 : fastcampus react & redux로 시작하는 웹 프로그래밍

profile
이것저것 합니다.

0개의 댓글