React_ Tesla 사이트 클론 - 1

이번엔 테슬라의 사이트를 클론코딩 해보려고 한다.
본래 클론코딩은 그저 따라만 하는것이라 의미가 없다고 생각했었고 어디서 대충 주워들은 이야기로는 클론코딩을 포트폴리오로 하는 개발자는 별로 좋게 보지 않는다고 들었던 것 같다.
하지만 클론코딩만큼 기초를 다지고 실력을 기르는것 만큼 좋은 수단은 없다고도 들었으니 이것은 개인의 의견차이인듯 하다.
나는 후자의 의견에 더 동의하기 때문에 이번 프로젝트를 진행해보려 한다.

npx create-react-app . --template redux

프로젝트를 만들어주자 이번엔 redux 템플릿으로 진행할 것이다.

테슬라의 화면을 보자

.상단 헤더 Nav바(로고, 상단메뉴, 우측메뉴(메뉴팝업))
.홈 화면
ㄴ텍스트
ㄴ버튼
ㄴ호버링 화살표

이정도 컴포넌트들로 구성되어 있다.
먼저 헤더를 만들어보자 components폴더와 Header.js를 만들자

import React from 'react'

function Header() {
  return (
    <div>Header</div>
  )
}

export default Header

기본 틀을 잡고 나서 App.js에 미리 import해두자

* {
  box-sizing: border-box;
  font-family: "Rubik", sans-serif;
  color: #393c41;
  margin: 0;
  padding: 0;
}

body {
  width: 100%;
}

또 간단한 css를 적용하고 보면

Header가 나온다.
동일하게 홈 화면 컴포넌트도 만들자 Home.js로 만들고 보면

잘 나온다.

이번 프로젝트에서는 styled-components라는 라이브러리를 이용할 것이다.

npm i --save styled-components

설치하고

import React from "react";
import styled from "styled-components";

function Home() {
  return <Container> Home</Container>;
}

export default Home;

const Container = styled.div`
  height: 100vh;
`;

간단한 코드를 작성해두자
테슬라 홈페이지에서 보면 홈 화면이 여러 섹션으로 구성되어있었다.
요 홈 자리에 섹션들을 채워 구성할 예정이므로 Section.js도 만들자. (import도 적절히 해주자)
이제 Home.js에서 텍스트 대신 Section을 넣어보면

  return (
    <Container>
      <Section />
      <Section />
      <Section />
    </Container>
  );


섹션들이 잘 나온다 Home.js는 섹션들을 받아서 보여주는 역할을 하고 세부적인건 Section.js에서 구성할 것이다.
헤더는 나중에 만져볼 것이니 잠시 숨겨주고 섹션을 조금만 꾸며보자

function Section() {
  return <Wrap></Wrap>;
}

export default Section;

const Wrap = styled.div`
  width: 100vw;
  height: 100vh;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-image: url("/images/model-3.jpg");
`;


배경이미지가 테슬라로 잘 나타난다.
styled-components는 css를 component안에서 작성 할 수 있게 해주는 라이브러리다.
자동완성을 지원하지 않는게 단점..
자세한 사용법은 공식 사이트 참고하자 https://styled-components.com/

추가로 url의 경우 기본폴더로 public을 참조하고 있으니
url("/public/images/model-3.jpg") 이 아닌
url("/images/model-3.jpg")다.
이제 텍스트도 넣어보자

    <Wrap>
      <ItemText>
        <h1>Model S</h1>
        <p>Order Online for Touchless Delivery</p>
      </ItemText>
    </Wrap>
  );
  ...
  ...
  const ItemText = styled.div`
  padding-top: 15vh;
  text-align: center;
`;


사진이 멋있으니 텍스트만 넣어도 멋있다. 배경은 모델3에서 모델s로 바꾸었다.

하단에 있던 버튼 2개를 만들자 버튼은 1그룹에 2개의 버튼이 있는 형식으로 만들 예정이다.

        <h1>Model S</h1>
        <p>Order Online for Touchless Delivery</p>
      </ItemText>
      <ButtonGroup>
        <LeftButton>Custom Order</LeftButton>
        <RightButton>Existing Inventory</RightButton>
      </ButtonGroup>
    </Wrap>
  );
}

버튼 이 될 코드를 추가하고


const ButtonGroup = styled.div``;

const LeftButton = styled.div``;

const RightButton = styled(LeftButton)``;

그에 해당하는 styled를 작성하자 마지막이 div가 아니라 LeftButton인 이유는 그의 css속성을 계승할것이기 때문.

죄다 위로 모여있다.. 스타일 코드가 없으니 당연한것.

const ButtonGroup = styled.div`
  display: flex;
`;

const LeftButton = styled.div`
  background-color: rgba(23, 26, 32, 0.8);
  height: 40px;
  width: 256px;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 100px;
  opacity: 0.85;
  text-transform: uppercase;
  font-size: 12px;
`;

const RightButton = styled(LeftButton)``;


그럴듯한 버튼이지만 위치가 이상하다.
저 버튼들은 Wrap이란 div안에 포함되어 있어 Warp에서 위치를 잡아줘야 한다.

const Wrap = styled.div`
  width: 100vw;
  height: 100vh;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-image: url("/images/model-s.jpg");
  display: flex;
  flex-direction: column;
  justify-content: space-between; // vertical
  align-items: center; // horizontal
`;
...
...
const ButtonGroup = styled.div`
  display: flex;
  margin-bottom: 30px;


의도한 대로 잘 나온다.
버튼 아래에 호버링 화살표를 만들어보자

        <RightButton>Existing Inventory</RightButton>
      </ButtonGroup>
      <DownArrow src="/images/down-arrow.svg" />
    </Wrap>
  );
}
const RightButton = styled(LeftButton)``;

const DownArrow = styled.img`
  margin-top: 20px;
  height: 40px;
`;

앞과 같이 추가하면

잘 나오긴 하는데 화면 구성이 이상해졌다.
해결법은 간단한데 ButtonGroup과 DownArrow를 다시 묶어주면 된다.

      </ItemText>
      <Buttons>
        <ButtonGroup>
          <LeftButton>Custom Order</LeftButton>
          <RightButton>Existing Inventory</RightButton>
        </ButtonGroup>
        <DownArrow src="/images/down-arrow.svg" />
      </Buttons>
    </Wrap>
  );
}
...

const Buttons = styled.div``;

버튼사이의 간격도 좀 넣어주자

  margin: 8px;


이제 화살표 애니메이션을 만들자

const DownArrow = styled.img`
  margin-top: 20px;
  height: 40px;
  animation: animateDown infinite 1.5s;
`;

애니메이션css를 추가하고 index.css에서

@keyframes animateDown {
  0%, 20%, 50%, 80%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(5px);
  }
  60% {
    transform: translateY(3px);
  }
}

만든 애니메이션의 키프레임을 넣어준다.
추가로 css를 조금 수정해주면

//index.css
body {
  width: 100%;
  overflow-x: hidden;
}

const DownArrow = styled.img height: 40px; overflow-x: hidden; animation: animateDown infinite 1.5s;;

잘 작동한다.
우측 버튼의 css도 바꿔주면

좀 더 나아졌다.
모바일 사용자를 위해 화면이 작을 경우 버튼을 세로로 배치하도록 하자

const ButtonGroup = styled.div`
  display: flex;
  margin-bottom: 30px;
  @media (max-width: 768px) {
    flex-direction: column;
  }
`;

@media는 화면이 지정한 크기보다 작을경우 실행한다.

이제 이 Section을 Home.js에서 여러개 생성해보면

function Home() {
  return (
    <Container>
      <Section />
      <Section />
      <Section />
    </Container>
  );
}


같은 섹션을 반복해서 만들수 있다.
그러나 우리는 각 섹션별로 다른 배경이나 컴포넌트롤 만들어줘야 하는데
이번 포스팅에선 여기까지 다루고 나머지는 다음 포스팅에서 다루자.

좋은 웹페이지 즐겨찾기