패스트캠퍼스 X 야놀자: 프론트엔드 개발 부트캠프_HTML/CSS 과제 디즈니플러스 클론 코딩 후기

지구·2023년 8월 7일
0

부트캠프

목록 보기
4/6
post-thumbnail

과제 소개

지금 수강하고 있는 패스트캠퍼스 X 야놀자: 프론트엔드 개발 부트캠프에서 첫 과제로 HTML과 CSS만을 이용한 클론 코딩을 하게되었다.
원하는 사이트(페이지)를 자유롭게 선택하고 레이아웃만 클론 코딩하면 되는 과제이다.

내가 주로 사용하는 사이트나 서비스를 클론해보자고 생각하여 스마트폰을 보던 중에 넷플릭스, 카카오톡, 패스트캠퍼스, 네이버 등 많은 것들이 있었지만 중복되는 요소가 많았고 CSS만으로 구현하기에는 어려워보였다.
적당한 수준의 사이트를 찾던 중에 최근에 가입한 디즈니 플러스 홈페이지를 들어갔는데 제일 상단 영역을 제외하고는 수업에서 배운 Flex를 적용하기도 괜찮아 보이고 중복되는 영역도 적어 다양한 레이아웃을 구현할 수 있을 것이라고 생각되어 디즈니 플러스를 클론하기로 결정했다.

필수 요구사항

  • 과제에 대한 설명을 포함한 README.md 파일을 제공하세요!
  • 과제 결과와 비교할 수 있는 실제 사이트(페이지)의 주소를 명시하세요!
  • 과정에서 사용한 프로젝트 폴더/파일이 모두 포함돼야 합니다, 일부 파일만 제출하지 마세요!
  • 실제 서비스로 배포하고 접근 가능한 링크를 추가해야 합니다.

선택 요구사항

  • <header><section> 등 시멘틱 태그를 최대한 활용해보세요.
  • 실제 사이트의 레거시 코드 활용보단 최신의 CSS Flex 혹은 Grid 등을 활용해보세요.
  • 부분적으로 BEM 방법론을 도입해보세요.
  • JS가 필요한 부분은 되도록 생략하되 이유를 명시해보세요.(CSS로 대체 가능한지 피드백이 있을 수 있겠죠?!)
  • JS가 필요한 부분 중 구현할 부분이 있다면 자유롭게 구현해보세요.(JS 과제가 아니니까 가볍게 구현하시길 추천해요)
  • SCSS 등의 CSS 전처리도구를 도입해보세요.
  • SCSS 컴파일에 Webpack이나 Parcel 같은 번들러를 활용해보세요.

과제 진행 기간 📆

2023.07.24(월) ~ 2023.07.28(금)

기술 스택 ⛏️

개발 환경

Visual Studio Code, Git, Github

사용 언어

HTML,CSS,JavaScript
HTML, CSS만을 사용하여 완성하는 것이 주된 과제의 내용이었지만 간단한 기능을 구현하기 위해서 JS를 약간 사용했다.

사이트 주소 🔗


클론한 화면 구성 🖥️

헤더 + 메인인기 콘텐츠
특징 + 배너기기
질문헤더 + 푸터
  • HTML, CSS만으로 구현하도록 노력했고 JS가 필요한 부분이 있다면 JS를 최소한으로 사용하여 구현했다.
  • <header>,<nav>, <main>, <section>, <footer> 등 시멘틱 태그를 최대한 활용하였다.
  • Flex를 주로 이용하여 레이아웃을 구성했다. 인기 콘텐츠 영역에서 Grid를 사용하고 싶었지만 모바일 반응형 레이아웃에서 9개의 이미지가 2줄로 정렬 되는데 마지막 이미지가 홀수가 되면서 가운데 정렬해야해서 Flex를 사용했다.

주요 기능 🔧

  1. 반응형

    2
    3

    CSS의 Media Query를 이용하여 모바일, 테블릿, 데스크탑으로 나누어 구현했습니다.

  2. 헤더 투명화

    1

    JavaScript와 CSS를 이용하여 특정 스크롤 영역에서 헤더와 버튼이 투명하도록 처리했습니다.

  3. 메인 이미지 전환 기능

    4

    <input>, <label>과 CSS만을 이용하여 메인 이미지 밑에 버튼을 클릭하면 콘텐츠 이미지가 전환되도록 구현했습니다.

  4. 질문 아코디언(펼침/닫힘) 기능

    5

    JavaScript와 CSS를 이용하여 질문 영역을 클릭하면 질문 상자가 열리거나 닫히도록 처리했습니다.

JS가 필요한 부분 ⚙️

  1. 헤더 투명화

    자바스크립트의 addEventListenerscrollwindow.scrollY를 사용하여 스크롤을 인식하여 상단 0~330px까지에서는 특정 클래스를 추가하여 CSS에 특정 클래스가 있다면 헤더와 버튼을 투명화 하도록 구현하였다.

    let header = document.getElementById("header");
    		let logo = document.getElementById("header-logo");
    		let signup = document.getElementById("header-signup");
    
    window.addEventListener("scroll", function () {
      if (window.scrollY < 330) {
        header.classList.add("hidden-header");
        logo.classList.add("hidden-item");
        signup.classList.add("hidden-item");
      } else {
        header.classList.remove("hidden-header");
        logo.classList.remove("hidden-item");
        signup.classList.remove("hidden-item");
      }
    });
  2. 질문 아코디언 기능

    자바스크립트의 getElementByIdaddEventListenerclick을 사용하여 질문 영역을 클릭하면 질문 <div> 태그 클래스 리스트에 open이 토글되어 클래스명에 open이 있다면 질문 아코디언을 펼치고 없다면 질문 아코디언을 닫는 기능을 구현하였습니다.

    let question1 = document.getElementById("question1");
    
    question1.addEventListener("click", () => click(question1));
    
    function click(question) {
    	question.classList.toggle("open");
    }
    
  3. 이미지 자동 전환 기능

    이미지가 시간이 지남에 따라 자동으로 전환되고 재생 / 일시정지 버튼을 클릭하면 이미지 자동 전환이 멈추거나 재생되어야 한다.
    이미지가 좌우로 정렬되어 있다면 CSS만으로 구현할 수 있겠지만 투명화로 전환해야하기 때문에 자바스크립트가 필요하다고 판단되어 구현하지 않았다.

리펙토링♻️

1. 상대경로

배포환경, 개발환경에 따라 경로가 제대로 적용되지 않는 경우가 발생하니 상대경로로 작성하는 습관을 가지라는 피드백

<link
      rel="icon"
      href="/assets/icons/favicon-32x32.3699...2fb883f.png"
/>

<link 
      rel="icon"
      href="./assets/icons/favicon-32x32.3699...2fb883f.png"
/>	

2. 불필요한 <div> 태그 제거

<input>, <button> 태그의 디자인이 원하는대로 되지 않고
<div> 태그로 한번 더 감싸야한다고 생각했는데 불필요하다는 피드백을 받고 수정했다.

<form class="email-form">
  <div>
    <input class="email-input" type="email" placeholder="이메일 주소" />
  </div>
  <div>
    <button class="email-button">구독하기</button>
  </div>
</form>

<form class="email-form">
  <input class="email-input" type="email" placeholder="이메일 주소" />
  <button class="email-button">구독하기</button>
</form>

3. 클래스 네이밍

클래스 네이밍이 구체적이지 않아서 코드만 보고 구별이 되지 않거나 비슷한 요소가 있다면 겹칠 수 있지 때문에 네이밍은 중요하다.
역할과 위치 등을 고려한 네이밍을 짓어야 한다.
이번 클론 코딩 프로젝트에서 가격은 한번만 나오기 때문에 문제가 되지 않지만 이후에 문제가 생길 수 있기 때문에 구체적인 네이밍 짓는 연습을 위해 수정했다.

<p class="price">
	*유료 멤버십 월 9,900원 / 연 99,000원<br />
    *연간 구독 시 최대 16% 할인된 가격
 </p>

<p class="main-price">
	*유료 멤버십 월 9,900원 / 연 99,000원<br />
    *연간 구독 시 최대 16% 할인된 가격
 </p>

4. 적절한 태그 사용

무분별한 <div> 태그 사용은 편하지만 나중에 볼 때는 불편 요소가 된다.
시멘틱을 위해서도 텍스트는 <span>, <p>태그를 이용하는 것이 좋다.
공통 CSS로 <p>margin-bottom: 20px으로 정했기 때문에 <div>를 사용했는데 부적절한 사용이라고 생각했다. 따라서 CSS 적용을 위해 클래스를 만들어 CSS를 적용해주었다.

<div class="slide-text-box">
  <div>아바타: 물의 길</div>
  <div>지금 스트리밍 중</div>
</div>

<div class="slide-text-box">
  <p class="slide-text">아바타: 물의 길</p>
  <p class="slide-text">지금 스트리밍 중</p>
</div>

5. 변하지 않는 값 선언

변할 가능성이 있는 값과 변하지 않는 값을 구분하여 constlet으로 선언해주어야 한다.

let header = document.getElementById("header");

const header = document.getElementById("header");

6. 반복되는 코드 반복문으로 간결화

querySelectorAll을 사용하서 찾으면 하나의 요소를 누르면 querySelectorAll로 찾아낸 모든 요소가 펼쳐질 것이라고 생각해서 전 코드로 작성했는데 멘토님의 코드 리뷰로 이 방법이 가능하다는 것을 알게되었다.

let question1 = document.getElementById("question1");
let question2 = document.getElementById("question2");
let question3 = document.getElementById("question3");
let question4 = document.getElementById("question4");
let question5 = document.getElementById("question5");

question1.addEventListener("click", () => click(question1));
question2.addEventListener("click", () => click(question2));
question3.addEventListener("click", () => click(question3));
question4.addEventListener("click", () => click(question4));
question5.addEventListener("click", () => click(question5));

const questions = document.querySelectorAll(".accordion-container");

for (const question of questions) {
  question.addEventListener("click", () => click(question));
}

7. 태그 선택자 지양

CSS를 브라우저가 파싱할 때, 선택자를 우측에서부터 읽는다. 그럼 모든 img 태그를 모두 찾은 다음에 적용을 하는 순서로 가기 때문에 태그 선택자를 지양해야 한다.
따라서, 아래와 같이 태그 선택자를 적절한 클래스를 만들어 클래스 선택자로 적용시켜 주었다.

.banner-box img {
	...생략
}

.banner-img {
	...생략
}

8. reset용 코드

공통 CSS에 reset용으로 color: white로 선언했는데 멘토님께서 reset용 코드라면 color: inherit이 맞다고 하여서 여쭤보니
'모든 태그를 white로 쓴다면 문제가 되지 않겠지만, 기획이나 디자인은 언제든 변경이 가능하기 때문에 그렇게 명시하는 건 좋은 습관은 아니다'라는 답변을 받았고 지금은 간단한 클론 코딩이라 문제가 되지 않지만 규모가 큰 프로젝트나 실제 프로젝트에서는 문제가 생길 수 있다는 것을 알게되었다.

a {
	color: white;
}

a {
	color: inherit;
}

오류 해결 법 ❗️

input[id="select_box1"]:checked ~ div #imgbox .select1 {
  opacity: 1;
}

버튼 클릭을 이용한 이미지 전환 기능을 구현하는 과정에서 ~(형제 선택자)를 사용하려는 태그끼리 한 태그 안에 있는 형제 태그여야(같은 부모에 속해있어야) 작동하는데 사용법을 정확히 공부하지 않아 다른 태크에 속해있어 원하는대로 동작하지 않는 것을 모르고 많은 시간이 걸렸다.

<div class="slide">
 <input type="radio" name="img_select" id="select_box1" checked />
   ~생략~
 <div class="slide-nav">
   <label class="label1" for="select_box1"></label>
   ~생략~
 </div>
 <button class="slide-btn"></button>
 <div>
   <ul id="imgbox">
     <li class="select_img select1">
       <div
         class="background mobile"
         style="
           background-image: url(/assets/images/main/revenant_m.jpeg);
         "
       ></div>
       ~생략~
     </li>
     ~생략~
   </ul>
 </div>
</div>

위 코드와 같이 input 태그와 div 태그 안에 있는 select1클래스를 slide 클래스를 가진 div 태그안에 넣어주어 문제를 해결했다.

느낀점 🧐

클론 코딩을 시작하기 전에는 쉽게 완료할 수 있을 줄 알았는데 생각보다 오랜 시간이 걸렸다.

JS 없이 CSS만으로 구현할 수 있는 기능이 생각보다 많다는 것을 알게되었다.

그와 동시에 CSS는 그때그때 필요한 것을 검색해서 사용하면 된다고 생각했으나 CSS 내장 기능의 존재 자체를 알고있는 것과 모르는 것의 차이는 크다는 것을 알게되었다.

형제 선택자, 인접 선택자 등의 존재와 사용법을 알게되어서 좋았고 다음 프로젝트에서도 유용하게 사용할 수 있을 것 같다.

처음으로 현업 개발자에게 코드 리뷰를 받았는데 멘토님께서 코드 리뷰를 꼼꼼히 해주셔서 많은 도움이 되었다.
생각도 못한 부분에서 놓치고 있던 부분도 있었고 간단하게 클린코드로 리펙토링 할 수 있는 부분도 있었다.

profile
프론트엔트 개발자입니다 🧑‍💻

0개의 댓글