Hi, I’m Kang Byeong-hyeon.

..

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




헤더와 드롭메뉴 - 검색

Input이 blur될 경우 스타일링 하기

스크린샷 2024-04-16 오후 3.23.03.png

transition - CSS: Cascading Style Sheets

Input이 focus될 경우 스타일링 하기

header .sub-menu .search {
  position: relative;
  height: 34px;
}

header .sub-menu .search input {
  width: 36px;
  height: 34px;
  padding: 4px 10px;
  border: 1px solid #ccc;
  box-sizing: border-box;
  border-radius: 5px;
  outline: none;
  background-color: #fff;
  color: #777;
  transition: width 0.4s;
}

header .sub-menu .search input:focus {
  width: 190px;
  border-color: #669900;
}

header .sub-menu .search .material-symbols-outlined {
  height: 24px;
  position: absolute;
  top: 0;
  bottom: 0;
  right: 5px;
  margin: auto;
}

자바스크립트로 Search Icon 클릭 시 이벤트 적용하기

input 영역을 focus하면 애니메이션이 적용되지만 Search Icon을 클릭하면 동작되지 않는 것을 확인할 수 있다.

이를 위해 자바스크립트를 통해 Search Icon을 클릭하면 Input에 focus되도록 구현해야한다.

추가로 focus될 경우 Search Icon은 보이지 않아야 되기 때문에 focus되거나 blur될때 투명도를 주는 .focus 클래스를 추가하고 삭제되도록 구현해야한다.

<script src="./js/main.js" defer></script>

script의 async, defer 속성의 차이

async

스크린샷 2023-05-01 오후 3.28.01.png

스크린샷 2023-05-01 오후 3.28.07.png

defer

스크린샷 2023-05-01 오후 3.33.01.png

스크린샷 2023-05-01 오후 3.33.07.png

const searchEl = document.querySelector(".search");
const searchInputEl = searchEl.querySelector("input");

searchEl.addEventListener("click", () => {
  searchInputEl.focus();
});
searchInputEl.addEventListener("focus", () => {
  searchEl.classList.add("focused");
  searchInputEl.setAttribute("placeholder", "통합검색");
});
searchInputEl.addEventListener("blur", () => {
  searchEl.classList.remove("focused");
  searchInputEl.setAttribute("placeholder", "");
});

즉, 자바스크립트는 DOM요소를 선택하고 특정 이벤트에 원하는 스타일링에 해당하는 클래스를 추가하거나 삭제하면서 요소를 동적으로 처리할 수 있도록 해준다.

결과

Apr-16-2024 16-46-33.gif




헤더와 드롭메뉴 - 메인 메뉴

특정 부분만 border-rardius 설정하기

header .main-menu .item:hover .item__name {
  background-color: #2c2a29;
  color: #669900;
  border-radius: 6px 6px 0 0;
}

레이어 최상단으로 끌어올리기

header .main-menu {
  display: flex;
  position: absolute;
  bottom: 0;
  right: 0;
  z-index: 1;
}

inner 클래스 분리하기

/* COMMON */
.inner {
  width: 1100px;
  margin: 0 auto;
  position: relative;
}

/* HEADER */
header > .inner {
  height: 120px;
}

CSS 이미지 불러오기

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

결과

Apr-21-2024 16-11-14.gif




BEM 방법론(Block Element Modifier)

예시

스크린샷 2024-04-21 오후 4.23.41.png

위는 요소 일부분에 대한 예시이다.

클래스 명을 .name처럼 단순하게 작명할 경우 중복될 가능성이 있다.

이를 Underscore를 사용하여 요소의 일부분을 나타낼 수 있다면, 해당 name이 container와 item요소 중 어떤 요소의 일부분인지를 클래스만 보고 빠르게 파악할 수 있게 된다.

스크린샷 2024-04-21 오후 4.23.50.png

위는 요소 상태에 관한 예시이다.

위와 같이 버튼의 세가지 상태가 버튼에 종속되어져 있다는 것을 사용자가 파악하기 어렵다.

이처럼, primary success error버튼에 종속되어져 있다는 것을 dash를 사용해서 나타낼 수 있다.

위와 같이 BEM방법론을 사용하게 되면 HTML의 구조를 확인하지 않고 클래스만 봐도 어떤 구조로 이루어져 있는지를 빠르게 파악할 수 있게 된다.




헤더와 드롭메뉴 - 전역 배지(GSAP)

배지 스타일링 및 위치 설정하기

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, 0, 0.15);
  cursor: pointer;
}

브라우저 상단에 고정시키기

header {
  position: fixed;
  top: 0;
  background-color: #f6f5f0;
  border-bottom: 1px solid #c8c8c8;
}

페이지 스크롤시 header를 브라우저 상단에 고정시키려면 position: fixed로 설정한다.

하지만 fixed로 설정하면 다음과 같이 width값이 최소한으로 잡혀진다.

그 이유는, position을 fixed나 absolute로 설정하게 되면 자동으로 width: auto로 설정되기 때문에, 가로 넓이를 최소한으로 잡으려고 한다.

스크린샷 2024-04-21 오후 4.46.24.png

이러한 문제를 해결하려면 width: 100%로 하여 부모 요소(body)의 width값으로 설정해야한다.

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

부모의 너비 만큼 header의 너비가 잡힌 것을 확인할 수 있다.

스크린샷 2024-04-21 오후 4.47.36.png

스크롤 시 배지 숨기기

스크롤값이 특정값을 넘어가게 될 경우 배지가 숨겨지도록 javasript를 통해 구현해야할 필요가 있다.

lodash.js

window에 scroll 이벤트를 주고 로직을 작성하면, 스크롤 할때 마다 함수가 연속적으로 호출된다.

그러나, 위처럼 구현하게 되면 사이트에 들어가는 컨텐츠가 많아 질수록 버벅이는 현상으로 이어질 수 있다.

이러한 방식을 해결해줄 수 있는 외부 라이브러리가 loadash.js이다.

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

위 링크를 통해 lodash.js 라이브러리 사이트의 CDN 페이지로 이동한다.

스크린샷 2024-04-21 오후 4.52.15.png

가장 많이 사용하는 첫번째 CDN을 복사해서 head태그 내부에 추가하고 다음과 같이 작성한다.

const badgeEl = document.querySelector("header .badges");

window.addEventListener(
  "scroll",
  _.throttle(() => {
    if (window.scrollY > 500) {
      badgeEl.style.display = "none";
    } else {
      badgeEl.style.display = "block";
    }
  }, 300)
);

GSAP

배지를 숨기고 보여지는 애니메이션 과정에서 이질감이 있다.

자연스러운 애니메이션 효과를 주기위해 GSAP 라이브러리를 사용할 수 있다.

Apr-21-2024 18-19-40.gif

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

위 링크를 통해 GSAP 라이브러리 사이트의 CDN 페이지로 이동한다.

스크린샷 2024-04-21 오후 6.15.00.png

가장 많이 사용하는 첫번째 CDN을 복사해서 head태그 내부에 추가하고 다음과 같이 작성한다.

window.addEventListener(
  "scroll",
  _.throttle(() => {
    if (window.scrollY > 500) {
      gsap.to(badgeEl, 0.6, {
        opacity: 0,
      });
    } else {
      gsap.to(badgeEl, 0.6, {
        opacity: 1,
      });
    }
  }, 300)
);

스크린샷 2024-04-21 오후 6.11.30.png

하지만 opacity값으로만 애니메이션을 처리하면, 요소는 그대로 남고 보이지 않는 형태가 되기 때문에 사용자가 해당 영역을 클릭하면 배지를 클릭하게되는 문제가 발생한다.

때문에 opacity 뿐만 아니라 displaynoneblock으로 옵션을 주어 요소를 완전히 제거할 수 있도록 설정해야한다.

window.addEventListener(
  "scroll",
  _.throttle(() => {
    if (window.scrollY > 500) {
      gsap.to(badgeEl, 0.6, {
        opacity: 0,
        display: "none",
      });
    } else {
      gsap.to(badgeEl, 0.6, {
        opacity: 1,
        display: "block",
      });
    }
  }, 300)
);

결과

Apr-21-2024 18-25-29.gif




소감

이번 주차는 loadash와 gsap 같은 오픈소스를 처음 접해보았는데, 처음에는 매우 생소하게 느껴졌다.

lodash를 사용하여 스크롤할 때 특정 주기를 설정하여 함수가 연속적으로 트리거되지 않도록 하는 방법을 배웠다.

뿐만 아니라 lodash에서 제공하는 객체와 배열 등의 데이터 구조는 일부 메서드에서 기존의 ES6보다 뛰어난 성능과 함수의 확장성을 제공한다는 것을 알게 되었다.

또한, gsap에서 제공하는 gsap.to(), gsap.from(), gsap.fromTo()를 사용하여 애니메이션을 보다 간단하게 설정할 수 있다는 점도 배울 수 있었다.