본문 바로가기

Frontend

16-1 스타벅스 클론 코딩하기 - Part1 헤더와 드롭다운 메뉴

fastcampus 사이트의 '한번에 끝내는 프론트엔드 개발 강의' 를 수강하며 공부 목적으로 작성하는 글입니다.

 

클론 코딩 완성형태

강의의 예제를 따라해보며 스타벅스 클론코딩을 해보았습니다. 한번에 많은 기능을 넣다보니 정리가 필요할 것 같아 파트별로 하나하나 요점들을 적어보려고 합니다.


순서

1. 헤더로고

2. 드롭 다운 메뉴

3. BEM

4. 전역 배지

 

● 헤더 로고

헤더로고 좌측상단에 배치하기

  

<header>
    <div class="inner">
      <a href="/" class="logo">
        <img src="./images/logo.png" alt="logo" />
      </a>
</header>

헤더 안에 inner 클래스를 따로 설정해 두어 영역을 나눠 줍니다. 그리고 CSS를 통해 헤더와 inner의 부분을 색깔로 구분해주면 보기 쉽습니다. inner의 스타일은 가로. 세로 길이를 설정하고 margin : 0 auto;의 값을 통해 가운데 정렬을 할 수 있습니다.(auto는 컴퓨터가 뷰 포트에 맞게 가운데 위치할 수 있도록 자동으로 가운데 정렬을 해주는 기능입니다.)

파란색은 헤더의 영역이고 주황색은 inner의 영역입니다. 

로고의 이미지를 세로의 중간에 위치하도록 하기 위해서는 CSS를 통해 몇 가지 설정해야 할 것이 있습니다.

이미지는 inline 속성을 가지는데 이를 display: block; 으로 변환을 시켜줘야 합니다. inline의 속성은 글자면 글자 칸 수 만큼, 이미지이면 이미지 크기만큼을 영역으로 할당하고 늘이거나 줄일 수 없습니다. 따라서 block 값을 주어 margin 값을 넣을 수 있도록 해줍니다. 그리고 로고의 부모요소인 inner position은 relative로 로고의 position은 absolute의 값을 주고, top: 0; bottom: 0; margin: auto 0 ; 값을 주면 가운데 정렬을 시킬 수 있습니다.

 

 

 

header part1

...

codepen.io

코드펜에 업로드 해놓았으니 이해가 되지 않는다면 확인해보세용..

 

 

▷ 헤더 서브메뉴 구성하기

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

그림과 같은 메뉴를 만들기 위해서는 여러개의 클래스로 구분지어 활용해야 합니다. 각각의 메뉴부터 search 바까지 sub-menu 하나, 각각의 메뉴 하나, 그리고 search 바까지 세개로 구성될 수 있겠네요.

 

우선 메뉴들을 한 줄로 만들기 위해 ul.menu 태그를 가진 CSS에다 display는 flex로 설정해줍니다.

메뉴 사이 사이 12px의 작은 선은 CSS 선택자 중 ::before라는 가상 선택자를 통해 만들 수 있습니다. ::before 가상선택자를 사용하며 꼭 추가해야하는 속성은 content 속성이었는데요. 이 속성이 CSS에 빠져 있으면 아무런 변화가 적용되지 않으니 꼭 추가해주세요. 그리고 가상선택자는 자동적으로 인라인 속성을 가지고 있습니다. 그러므로 블럭 속성으로 변경하기 위해서는 display: block으로  속성을 변경해주거나, position의 값을 fixed나 absolute로 주어 block 속성을 갖도록 해주어야합니다.

 

 

header part2

...

codepen.io

 

 

▷ 헤더 서치바 구현하기

확인해야 할 점

1. 아이콘 클릭시 화면이 늘어남

2. 클릭하면 아이콘은 없어지고 placeholder를 통해 '통합검색' 이라는 단어 출력

 

이 두가지를 유념하며 스타일을 적용해야합니다. 하지만 이 부분은 CSS만 사용해서 꾸미기에는 어려움이 있어 JS를 사용하여 구현하여야 합니다.

 

 <div class="search">
    <input type="text" />
      <div class="material-icons">search</div>
  </div>

확인해야할 점 1번에 강조를 준 이유는 CSS 스타일만 적용할 시에 input 박스만 누를 때 변화가 생기고, 아이콘을 누르면 아무런 반응이 없습니다. 두 개의 클래스가 다르기 때문에 발생하는 것인데 이는 JS를 통해서 추가적으로 다뤄야합니다.

JS 파트를 살펴보도록 할게요.

 

------------------------------------- 아이콘 클릭 시 화면 늘어남 ------------------------------------------------------
const searchEl = document.querySelector('.search');    //.search 클래스를 가진 태그 검색
const searchInputEl = searchEl.querySelector('input');  // 위에서 찾은 태그 내에서 input 요소 검색

searchEl.addEventListener('click', function () {  //행동추가하기. '클릭'시에 함수 실행
  searchInputEl.focus();  //input 요소를 focus 하겠다. 따라서 input 요소 하위에 있는 아이콘을 클릭해도 적용 
});

-------------------------------------아이콘 사라짐, placeholder 설정--------------------------------------------------
searchInputEl.addEventListener('focus', function () {  //input 요소가 focus 상태이면
  searchEl.classList.add('focused');  // 클래스 명에 'focused'를 추가
  searchInputEl.setAttribute('placeholder', '통합검색');  // 속성 추가
});
// 아이콘이 사라지는 효과는 CSS header .sub-menu .search.focused .material-iconst 선택자에서 별도로 지정할 것

searchInputEl.addEventListener('blur', function () {  //focused의 반대 의미는 'blur'
  searchEl.classList.remove('focused');  //포커스가 해제되면 클래스명에 'focused' 제거
  searchInputEl.setAttribute('placeholder', ''); //placeholder에는 내용 없음으로 변경
});

 

 

header part3

...

codepen.io

 

▷ 헤더 고정하기

헤더 영역은 휠을 내리든 올리든 항상 상단에 위치해야합니다. 따라서 헤더의 CSS를 설정해줘야합니다.

그러기 위해서는 position의 값을 fixed로 변경해야하는데요. 여기서 중요한 점이 하나 있습니다.

position이 relative 일 때 width의 값이 auto이면 가로 너비는 최대한 넓어지려는 성격을 가지지만, position이 fixed나 absolute이면 최소한으로 줄어들려는 속성을 가지고 있습니다. 그래서 width의 값을 auto 대신 100%로 변경하여 최대 너비를 가질 수 있도록 해야합니다.

 

 

● 드롭다운 메뉴

 

 

▷ 메뉴

<ul class="main-menu">
    <li class="item">
      <div class="item__name">COFFEE</div>
      <div class="item__contents">
        <div class="contents__menu"></div>
        <div class="contents__texture"></div>
      </div>
    </li>
</ul>

메뉴의 구성은 ul 태그의 main-menu 클래스 li 태그의 item클래스가 있고 안에 메뉴 이름을 담는 item__name 클래스와 드롭다운 메뉴부분에 해당하는 item__contents 클래스로 구성되어 있습니다.

 

메뉴를 만들며 주의해야할 점

  1.  메뉴의 hover 선택자의 영역을 지정할 때  item__name 클래스가 아닌 부모 클래스의 item클래스에 선택자를 두어 마우스가 드롭다운 메뉴에서 이동하더라도 작동되도록 할 것
  2.  z-index를 통해 드롭다운 메뉴가 전역배지보다 앞에 뜨도록 설정할 것
  3. 드롭다운 메뉴는 페이지의 위치에 상관없이 항상 메뉴 아래 위치에 고정적으로 뜰 수 있도록 position값을 fixed로 설정할 것

입니다.

 

▷ 드롭다운메뉴

 

위의 사진처럼 드롭 다운메뉴를 고정시키기 위해서 CSS로 설정해주어야합니다.

header .main-menu .item .item__contents{
  width: 100%;
  position: fixed; /*뷰포트를 기준으로 배치하겠다.*/
  left: 0;
  display: none
}
header .main-menu .item:hover .item__contents{
  display: block;
}

display를 none으로 설정해줌으로써 평소에는 뜨지 않다가 마우스가 메뉴를 가리킬 때 block으로 설정하여 뜨도록 하면 드롭다운 메뉴를 만들 수 있습니다.

 

 

그 외에는 위 사진처럼 구조를 만든다면 쉽게 할 수 있습니다.

 

 

● BEM(HTML 클래스 속성의 작명법)

→ Block Element Modifier

요소__일부분   : Underscore(Lodash) 기호로 요소의 일부분을 표시한다는 의미

 요소--상태   : Hyphen(Dash) 기호로 요소의 상태를 표시한다는 의미

 

<div class="container">
  <div class="name"></div>
  <div class="item">
    <div class="name"></div>
  </div>
</div>

요소__일부분 에 대해 위를 예시로 들겠습니다.

CSS로 처리할 때 보통 .container .name으로 선택자를 입력하는 경우가 있습니다. 하지만 이는 container 자식의 name과 item 자식의  name을 모두 가리키게 됩니다. 따라서 이러한 문제를 처리하기 쉽도록 요소__일부분 의 형태로 고쳐서 사용합니다.

 

위의 예시를 변경한다면

<div class="container">
  <div class="container__name"></div>
  <div class="item">
    <div class="item__name"></div>
  </div>
</div>

이 되는 거죠.

 

<div class="btn gold"></div>
<div class="btn white"></div>
<div class="btn brown"></div>

 요소--상태 의 경우를 예시를 들겠습니다.

버튼의 클래스명과 별도의 클래스명이 하나씩 더 들어있네요. 하지만 이들이 무엇을 의미하는지 명확하지 않습니다. 따라서 이 둘의 관계가 연결관계가 있다면 btn--을 넣어

<div class="btn btn--gold"></div>
<div class="btn btn--white"></div>
<div class="btn btn--brown"></div>

나타내어 준다면 의미전달을 확실히 할 수 있습니다.

 

● 전역배지

전역배지를 만들면서 생각해야하는 부분은 항상 상단에 위치하지만 스크롤을 내리면 서서히 사라지도록 동작시켜야 하는 부분입니다. 이 부분은 JS를 통해서 동작시킬 수 있는데 lodash.js 라이브러리를 사용한다면 쉽게 동작시킬 수 있습니다.

 

lodash.js - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers

A utility library delivering consistency, customization, performance, & extras. - Simple. Fast. Reliable. Content delivery at its finest. cdnjs is a free and open-source CDN service trusted by over 12.5% of all websites, serving over 200 billion requests e

cdnjs.com

위의 사이트에서 min.js 를 copy해 index.html에 붙여주세요.

 

lodash 라이브러리에서 제가 사용할 함수는 바로 _.throttle()이라는 함수입니다. 이 안의 매개변수는 함수, 시간이 들어가게 됩니다. 이 함수는 정해진 시간마다 함수가 동작하라는 의미를 가지고 있습니다. 즉, 이 함수를 쓰지 않는다면 계속해서 함수가 동작하여 느려지는 현상이 있겠지만, _.throttle()함수를 사용하면 특정시간마다 함수가 동작해 필요하지 않은 함수의 동작을 줄일 수 있게 됩니다.

 

다음 단계는 전역배지가 서서히 사라지도록 또 다른 JS라이브러리를 사용해야하는데요. 해당 함수는 gsap이라는 JS라이브러리 안에 있습니다.

 

 

 

gsap - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers

GSAP is a JavaScript library for building high-performance animations that work in **every** major browser. Animate CSS, SVG, canvas, React, Vue, WebGL, colors, strings, motion paths, generic objects...anything JavaScript can touch! No other library delive

cdnjs.com

마찬가지로 min.js 를 copy하여 index.html에 붙여 사용할 수 있습니다.

여기서 사용하는 함수는 gsap.to()라는 함수입니다. 매개변수로는 요소, 지속시간, 옵션(객체 데이터 사용)이 들어가는데 애니메이션을 처리할 요소와 지속시간, 그리고 애니메이션을 어떻게 처리해야할지에 대한 옵션을 입력해주면 됩니다.

 

전역배지 JS 처리 내용입니다.

const badgeEl = document.querySelector('header .badges');     //헤더에 badges 클래스 찾기
window.addEventListener('scroll', _.throttle(function () {
// 화면이 scroll 될 때마다 throttle을 걸어 해당 함수 실행
  console.log(window.scrollY);  //스크롤의 위치를 수치로 나타내기
  if (window.scrollY > 500){  
    //배지 숨기기    
    gsap.to(badgeEl, .6, {        //gsap.to(요소, 지속시간, 옵션);
      opacity: 0,
      display: 'none'
    });
  }else {
    //배지 보이기
    gsap.to(badgeEl, .6, {
      opacity: 1,
      display: 'block'
    });
  }
}, 300));
// _.throttle(함수, 시간)

 

정리

강의를 들어본 후 한번 더 수강하며 복습을 하고 정리를 해보았습니다. 강의 내용을 무작정 따라하기만 해서는 익숙해지지 않더군요. 강의를 두번 들으며 스스로 만들어보고 복습해보니 그나마 정리가 되는 것 같습니다. 

 

공부하며 느낀점을 정리해보자면

1. 웹페이지를 무작정 만들기보다는 파트별로 세세히 나누어 클래스명을 지정하는 것이 바람직합니다. 

2. html을 다 만들고 스타일을 수정하는 것보다 동시에 작업하는 것이 훨씬 수월합니다.

3. CSS를 작업할 때는 HTML에서 클래스를 생성할 때 CSS에서도 생성해주어 적용시키기 편하도록 하는 것이 좋습니다.