시작하기에 앞서

클론코딩하면서 관련 내용을 작성하는 것이 의외로 시간을 많이 할애해야 되는 작업이였군요... 조금 힘들지만 미래의 저를 위해 기록으로 열심히 남겨봅니다...

카카오 홈페이지와 동기화를 할 것인가?

동기화? 그 의미는 카카오 홈페이지의 최신 내용과 제 클론코딩 사이트에서의 내용을 동일하게 일치시킬지에 대한 문제입니다.


개발자 도구 - 네트워크탭에서 확인되는 요청URL을 통해 데이터를 가져오고, js에서 dom을 조작하여 데이터에 기반한 내용으로 작성할 수 있습니다. 뉴스와 관련된 데이터도 있지만, 살펴보면 category등 페이지 구성에 필요한 모든 데이터를 네트워크로 요청해서 받아와서 처리하는 것을 볼 수 있습니다(보통 이 작업을 처리하는 방법에 따라 비동기 통신 또는 동기 통신 이라고 부르는 것 같고, 네트워크 통신을 통해 데이터를 관리하는 것도 프론트엔드 분야에서 중요한 역량인 것 같습니다).

비동기 통신, 동기 통신에 대해 궁금하신 분들이 있을 경우 아래 블로그 글을 참고하셔도 좋을 것 같습니다.
https://inpa.tistory.com/entry/WEB-%F0%9F%8C%90-%EB%B9%84%EB%8F%99%EA%B8%B0Async%ED%86%B5%EC%8B%A0-%EB%8F%99%EA%B8%B0Sync%ED%86%B5%EC%8B%A0


제가 요청URL인 https://www.kakaocorp.com/api/v1/content/home?lang=KOR 을 통해 get요청을 해도 해당 데이터를 응답받을 수 있기 때문에 클론코딩 사이트에서도 활용해서 구현 가능합니다(일반 사용자, 즉 제가 아니여도 가능합니다). 단, 그렇게 하기 위해서는 fetch APIaxios등을 통해 통신해서 데이터를 가져와야되고 js를 사용해야되는 영역입니다. 이렇게 하나 하나씩 다 하면 실제 사이트의 모든 부분을 클론 코딩하게 될 것 같았고, 이번 과제에서는 특정 날짜에서 카카오 랜딩 페이지에서 보여주는 화면을 기준으로 클론코딩하도록 하겠습니다. 나중에 개선한다면 할 수 있겠지만 js중심의 과제가 아니기 때문에 이 과제에서 필요하다고 생각되는 js 구현(메뉴 클릭시 하위 메뉴 나타남: 레이아웃을 위해 필요하다고 생각하여 구현함)이 아닐 경우 하지 않도록 하겠습니다.

refactoring

(scss, css) inner 클래스 사용

header가 아닌 main 영역도 가운데로 위치한 형태로 화면에 출력되야 되기 때문에 공통 클래스인 inner를 만들어서 재사용하는 구조로 수정했습니다.

.inner {
  max-width: 1296px;
  margin: 0 auto;
}

또한, mobile을 제외한 breakpoint에서 자연스러운 inner 스타일의 적용을 위해 관련한 media 쿼리도 추가했습니다.

@media screen and (max-width: 1439px) {
  .inner {
    max-width: 952px;
  }
}

스크롤을 해도 header 영역이 가려지지 않도록 z-indexbackground-color를 설정하였습니다.

.landing_header {
  /* ... */
  z-index: 999;
  background-color: #fff;
  /* ... */
}

(js) event handling

  • 중복을 줄이고 재사용해서 사용하기 위해 findActiveNavMenu 함수 작성 및 호출
  • 등록하는 이벤트를 줄이고 유지보수를 위해 nav 요소에 이벤트를 위임하는 것으로 변경
const attachNavMenuEvent = () => {
  /* 
    - 중복성을 줄이고 재사용 하기위해 findActiveNavMenu함수를 만들어서 사용
    - nav element를 parent인자로 주는 것을 전제로 해서 작성함
    - nav element의 클래스 이름(.on)을 활용해서 활성화된 list item을 반환
      없을 경우 undefined 반환
  */
  const findActiveNavMenu = (parent) => {
    const menu_items = Array.from(parent.children).slice(0, -1);
    const activedMenu = menu_items.find((menu_item) =>
      menu_item.classList.contains("on")
    );
    return activedMenu;
  };

  const $nav_menu_list = document.querySelector(".gnb_list");

  const notExpandMenuTitles = ["뉴스"];

  /*
    - nav 요소에 Event delegation (이벤트 위임) 적용
    - 처음에는 li 요소에 개별적으로 이벤트를 적용했으나,
      최적화 및 유지보수를 위해 이벤트 위임을 활용하는 방식으로 변경함  
  */
  $nav_menu_list.addEventListener("click", (e) => {
    if (e.target === e.currentTarget) return;
    const title = e.target.textContent;
    if (notExpandMenuTitles.includes(title)) return;

    const activedMenu = findActiveNavMenu(e.currentTarget);
    if (activedMenu && activedMenu !== e.target.parentElement) {
      activedMenu.classList.remove("on");
    }

    /* 
     - a tag영역을 li 요소의 전체영역으로 설정했기 때문에, 
       li를 클릭했을 때 target은 a tag 요소가 됨
     - li > a 인 구조이기 때문에 e.target.parentElement는 li 요소가 됨
     - li 요소에 on클래스를 활용해서 메뉴 펼침을 제어하기 때문에,
       li 요소의 클래스를 toggle하여 제어
    */
    e.target.parentElement.classList.toggle("on");
  });

  /*
    - dim 영역(nav외의 영역)을 클릭했을 때 펼쳐진 메뉴가 있을 경우,
      해당 메뉴를 닫기 위해 이벤트 등록
    - 버블링 이벤트시 nav -> window 순서로 이벤트가 전파되기때문에 
      nav menu를 클릭했을 때 영향을 받을 수 있겠다고 생각함 
      -> 캡쳐이벤트 사용
  */
  window.addEventListener(
    "click",
    (e) => {
      const activedMenu = findActiveNavMenu($nav_menu_list);
      if (!activedMenu) return;
      if (e.target !== activedMenu.querySelector("a")) {
        activedMenu.classList.remove("on");
      }
    },
    true
  );
};

attachNavMenuEvent();

main 영역

main이라는 이름에 걸맞게 다른 영역보다 많은 시간을 할애하고 있는 영역입니다.

분석하면서

부드러운 애니메이션 효과에 신경을 (많이) 썼다는 느낌을 받았습니다.
예를 들면 아래와 같이

화면이 줄어들어 breakpoint에 도달하면 애니메이션으로 위치가 이동(transition)하고 이를 위해 position으로 각각 위치를 지정한 것을 확인할 수 있었습니다(한땀한땀 정성을 들이는 장인정신...).


이를 고려해서 처음부터 해당 카드 요소의 컨테이너 측에 relative, 카드 요소를 absolute로 배치한 것을 확인할 수 있고


breakpoint에 도달하면 absolutetop, left 의 포지션을 수정해서 transition을 통한 애니메이션을 적용합니다.

제가 왜 이렇게 구체적으로 얘기하냐면... 네... 이거 구현하기 위해 생각보다 많은 시간을 할애했기 때문입니다 ㅜㅜ

보통 애플이 이런 측면에서 변태적?인 것 같다는 말을 하는 것을 들을 수 있었는데, 카카오도 ... ?

card

카카오 홈페이지에서 동일한 구조로 보여지는 저 스타일을 일반적으로 card 또는 card 컴포넌트라고 부르는 것 같습니다.
css에서 사용하기 위해서는 card라는 클래스를 만들어서 사용해야 된다고 생각하여 관련 스타일링을 위한 작업을 하게 되었습니다.

  • 구조
    보통은 wrapper요소, 해당 content 요소 2개로 구분해서 작업을 했었는데, 유지보수 및 구현을 위해 container요소, wrapper요소, card요소 3개로 구분하여 구현했습니다.

    • container

      card를 활용한 영역을 구분하기 위해 작성하였고, container에서 외부 여백등에 대한 스타일링을 하여 나중에 수정이 필요할 때 손쉽게 하기 위한 구조라고 볼 수 있습니다. box-sizing: border-box 를 통해 wrapper요소가 container에서 padding 등을 제외한 크기를 가질 수 있도록 합니다. 또한 부모 요소인 aticledisplay: flex, card containerflex:1 을 적용하여 flex 에 기반한 구조를 가지고 있습니다. card containermax-width, min-width를 적용하여 카드가 사용되어지는 영역에 대한 크기를 제한합니다.

    • wrapper

      card 요소가 차지해야 되는 width를 가지며, card의 외곽요소(border 등)에 대한 적용이 되는 영역입니다.

    • card

      실제 card의 내용이 되는 영역입니다. padding을 통해 여백을 가지며, 저는 여기서 추가적으로 제목 등의 영역을 구분하고자 card header 클래스를 사용하고 html 구조를 작성하였습니다.

이후의 내용은 다음 포스트를 통해 다룰수 있도록 하겠습니다 ㅜㅜ

profile
$ npm run dev:ryan

0개의 댓글