5-3. 헤더 구성 하기
이번엔 헤더 컴포넌트를 만들어주겠습니다. 리액트 컴포넌트 스타일링에 필요한 styled-components
와 open-color
를 설치하세요.
$ yarn add styled-components open-color
index.css 수정
배경에 색을 설정하고, 전체적인 box-sizing
값을 border-box
로 설정하겠습니다 (이 설정은 엘리먼트를 스타일링 하게 될 때에, 테두리와 패딩이 실제 주어진 height 혹은 width 값에 영향을 끼치지 않게 해줍니다). 추가적으로, 로고에서 사용하기 위한 폰트 Rajdhani 를 구글 폰트에서 불러와서 사용하겠습니다. 구글 폰트에 들어가서 여러분이 원하는 폰트를 직접 선택하셔도 됩니다.
src/index.css
@import url('https://fonts.googleapis.com/css?family=Rajdhani:700');
body {
margin: 0;
padding: 0;
font-family: sans-serif;
box-sizing: border-box;
background: #f1f1f5;
}
*, *:before, *:after {
box-sizing: inherit;
}
그 다음엔, 헤더 컴포넌트를 만들겠습니다. 우리가 앞으로 만들 헤더 컴포넌트는 이렇게 생겼습니다:
왼쪽에 로고가 있고, 우측에는 로그인 버튼을 보여주며, 로그인시에는 유저 프로필 이미지 썸네일을 보여줍니다.
스타일 유틸 만들기
화면 사이즈에 따른 media 쿼리를 통한 자동 리사이징, 그리고 그림자 효과를 더욱 쉽게 주기 위하여 스타일 유틸을 만들도록 하겠습니다.
lib 디렉토리에 styleUtil 파일을 만들어서 다음 코드를 입력하세요.
src/lib/styleUtil.js
import { css } from 'styled-components';
// 미디어 쿼리 헬퍼: https://www.styled-components.com/docs/advanced#media-templates 참조
export const sizes = {
wide: '1200px',
desktop: '992px',
tablet: '768px',
phone: '376px'
};
export const media = Object.keys(sizes).reduce((acc, label) => {
acc[label] = (...args) => css`
@media (max-width: ${sizes[label]}) {
${css(...args)}
}
`;
return acc;
}, {});
// 그림자 효과: https://codepen.io/sdthornton/pen/wBZdXq 기반
export const shadow = (weight) => {
const shadows = [
css`box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);`,
css`box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);`,
css`box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);`,
css`box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);`,
css`box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22);`
];
return shadows[weight];
};
Header 컴포넌트 틀 만들기
헤더 컴포넌트는 src/components/Base 디렉토리에 저장하도록 하겠습니다. Base 디렉토리에는, 헤더컴포넌트, 유저메뉴 등 서비스 유저인터페이스의 기반에 관련한 컴포넌트들을 저장합니다.
그리고, 헤더 컴포넌트에서 사용 할 내부 컴포넌트 (로그인버튼과 유저썸네일)들도 있기 때문에, Header 디렉토리를 안에 만들어서 컴포넌트를 만들도록 하겠습니다.
src/components/Base/Header/Header.js
import React from 'react';
import styled from 'styled-components';
import oc from 'open-color';
import { shadow, media } from 'lib/styleUtils';
// 상단 고정, 그림자
const Positioner = styled.div`
display: flex;
flex-direction: column;
position: fixed;
top: 0px;
width: 100%;
${shadow(1)}
`;
// 흰 배경, 내용 중간 정렬
const WhiteBackground = styled.div`
background: white;
display: flex;
justify-content: center;
height: auto;
`;
// 해더의 내용
const HeaderContents = styled.div`
width: 1200px;
height: 55px;
display: flex;
flex-direction: row;
align-items: center;
padding-right: 1rem;
padding-left: 1rem;
${media.wide`
width: 992px;
`}
${media.tablet`
width: 100%;
`}
`;
// 로고
const Logo = styled.div`
font-size: 1.4rem;
letter-spacing: 2px;
color: ${oc.teal[7]};
font-family: 'Rajdhani';
`;
// 중간 여백
const Spacer = styled.div`
flex-grow: 1;
`;
// 하단 그래디언트 테두리
const GradientBorder = styled.div`
height: 3px;
background: linear-gradient(to right, ${oc.teal[6]}, ${oc.cyan[5]});
`;
const Header = ({children}) => {
return (
<Positioner>
<WhiteBackground>
<HeaderContents>
<Logo>HEURM</Logo>
<Spacer/>
{children}
</HeaderContents>
</WhiteBackground>
<GradientBorder/>
</Positioner>
);
};
export default Header;
이 컴포넌트의 우측에는, children
을 통하여 동적으로 렌더링하도록 설정하였습니다. 로그인/비로그인 상태에 따라 다른 결과물이 렌더링 되지요.
다음엔, 헤더 컴포넌트를 위한 인덱스파일을 만들겠습니다.
src/components/Header/index.js
export { default } from './Header';
헤더 컴포넌트에서는 어느정도의 상태관리가 필요합니다. 비로그인 상태에서는 로그인버튼을 보여주고, 로그인 상태에서는 유저썸네일을 보여줘야하기 때문이죠. 따라서, 리덕스 상태에 연결 된 컨테이너 컴포넌트를 만들겠습니다.
src/containers/Base/HeaderContainer.js
import React, { Component } from 'react';
import Header from 'components/Base/Header';
class HeaderContainer extends Component {
render() {
return (
<Header>
Hi
</Header>
);
}
}
export default HeaderContainer;
리덕스 연결은 나중에 하도록 하겠습니다. 이렇게 컨테이너 컴포넌트를 만들고 이 컨포넌트를 App 에서 불러와서 렌더링하세요.
src/App.js
import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import { Home, Auth } from 'pages';
import HeaderContainer from 'containers/Base/HeaderContainer';
class App extends Component {
render() {
return (
<div>
<HeaderContainer/>
<Route exact path="/" component={Home}/>
<Route path="/auth" component={Auth}/>
</div>
);
}
}
export default App;
우측에 Hi 가 나타났지요?
이제 Hi 대신에 로그인 페이지로 이동시켜주는 버튼을 만들어서 보여주겠습니다.
로그인 버튼 만들기
로그인 버튼은 react-router 의 Link
컴포넌트를 기반하여 만들도록 하겠습니다. 이미 만들어진 컴포넌트를 styled 를 통하여 스타일링 할 때는 다음과 같은 방식으로 합니다:
styled(Link)`
background: black;
`
그럼 어디 한번 만들어볼까요?
src/components/Base/Header/LoginButton.js
import React from 'react';
import styled from 'styled-components';
import oc from 'open-color';
import { Link } from 'react-router-dom';
import { shadow } from 'lib/styleUtils';
const BorderedButton = styled(Link)`
font-weight: 600;
color: ${oc.cyan[6]};
border: 1px solid ${oc.cyan[6]};
padding: 0.5rem;
padding-bottom: 0.4rem;
cursor: pointer;
border-radius: 2px;
text-decoration: none;
transition: .2s all;
&:hover {
background: ${oc.cyan[6]};
color: white;
${shadow(1)}
}
&:active {
/* 마우스 클릭시 아래로 미세하게 움직임 */
transform: translateY(3px);
}
`;
const LoginButton = () => (
<BorderedButton to="/auth/login">
로그인 / 가입
</BorderedButton>
);
export default LoginButton;
styled 로 꾸며진 Link 컴포넌트는, Link 와 똑같이 작동하기 때문에, 여기에 to
값을 설정하여 이동 할 경로를 설정해주면 됩니다.
이제 이 컴포넌트를 인덱스에 추가하고, HeaderContainer 에서 불러와서 렌더링하세요.
src/components/Base/Header/index.js
export { default } from './Header';
export { default as LoginButton } from './LoginButton';
src/containers/Base/HeaderContainer.js
javascript
이제 헤더 컴포넌트의 기본적인 디자인은 끝났습니다.
다음 단계로 넘어가서, 헤더 컴포넌트를 회원인증 페이지에선 숨기는 기능을 구현하겠습니다.