[React]Styled-Component

JH Cho·2022년 10월 3일
0

React

목록 보기
21/27

1. CSS-in-JS

1-1 정의

CSS-in-JS는 JS 파일 내에서 CSS를 작성할 수 있는 방법.

1-2 특징

CSS-in-JS는 js 파일 내에서 css 코드를 작성하기 때문에 css의 변수와 함수를 그대로 사용 가능. 그리고 css 클래스명을 해시 값으로 자동 생성하여 주기 때문에 클래스 이름 작명에 대한 수고가 감소함. 또한 컴포넌트와 스타일을 하나의 파일에서 관리하는 CSS-in-Js는 모듈화가 수월함.

1-3 이용추세

CSS-in-JS는 여러 라이브러리가 있고 그 중 가장 인기있는 것이 styled-component.

2. 스타일드 컴포넌트 특징

2-1 설치

프로젝트 시작 폴더에서
npm install styled-components

2-2 정의

// App.js

import React from 'react';
import styled from 'styled-components';          // 1

const App = () => {
  return <Title>styled-components!!</Title>;    // 2
};

const Title = styled.h1`       ⌉
  font-size: 32px;             |
  text-align: center;          |  // 3
  color: purple;               |
`;export default App;
  1. styled-components의 styled를 import
  2. UI가 그려지는 return문 내에 위와 같이 html 태그와 유사한 형태로 컴포넌트를 만들어서 선언.
    ex)<LogoImage src="/images/logo.png" alt="로고"/>
    주의) 파스칼 케이스로 작명하기
  3. 아래와 같이 styled 객체에 Tagged Templete 문법을 활용하여 css 속성 정의
const [컴포넌트명] = styled.[html태그]`
  [부여하고자 하는 css속성]
`;

3. 스타일드 컴포넌트 활용

3.1 props 활용

// App.js

import React, { useState } from 'react';
import styled, { css } from 'styled-components';

const App = () => {
  const [changeColor, setChangeColor] = useState(false);

  const handleChanageColor = () => {
    setChangeColor(!changeColor);
  };

  return (
    <>
      <Button onClick={handleChanageColor} primary={changeColor}> // props 전달
        Button
      </Button>
    </>
  );
}

const Button = styled.button`
  padding: 20px;
  margin: 10px;
  border: none;
  background-color: ${(props) => (props.primary ? "purple" : "pink")}; // 1
`;           // props 동적으로 사용              

export default App;

3.2 상속 스타일

const [새로운 컴포넌트명] = styled(기존컴포넌트명)`
 	[부여하고자 하는 css 속성]
`;

예시)

// App.js

const App = () => {
  return (
    <>
      <Button>Button</Button>
      <NewButton>New Button</NewButton>
    </>
  );
};

const Button = styled.button`      
  margin: 20px;
  padding: 20px;
  border: none;
  background-color: yellow;
  font-size: 20px;
`;

const NewButton = styled(Button)`  
  color: white;
  background-color: purple;
`; // color와 background-color외에는
   // 기존 Button과 같은 속성을 공유함

export default App;

개발자 도구 확인


// Elements

<button class="sc-bczRLJ jgCBVB">Button</button>   // 1
<button class="sc-bczRLJ sc-gsnTZi jgCBVB hXQPTY">New Button</button> // 2
  1. <Button> 컴포의 class가 jsCBVB
  2. <NewButton> 컴포의 class는 jgCBVB hXQPTY로 <BUTTON>컴포넌트의 스타일이 적용 됨.

LINK, 아이콘 라이브러리 등 외부 라이브러리 컴포넌트도 import하면 아래처럼 사용 가능

// App.js

import { Link } from 'react-router-dom';
;import styled from 'styled-components';

const App = () => {
  return <CartLink to="/cart">장바구니</CartLink>;
};

const CartLink = styled(Link)`
  color: red;
`;

export default App;

// Elements

<a class="sc-eCYdqJ gubPie" href="/cart">장바구니</a>

3.3 네스팅

스타일드 컴포넌트도 아래와 같이 네스팅 가능.
하지만 스타일 컴포넌트는 컴포넌트를 분리, 모듈화하기에 최적화되어있기 때문에 하나의 컴포넌트로 분리해서 사용하는 것이 좋다.

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

const Main = () => {
  return (
    <List>
      <li>
        메뉴<a href="http://list">클릭</a>
      </li>
    </List>
  );
};

const List = styled.ul`
  padding: 0;

  li {
    padding: 10px 0;
    color: red;
    font-size: 30px;

    a {
      color: green;
    }
  }
`;

export default Main;

네스팅이 필요한 경우도 있음.
react-slick과 같은 외부 라이브러리를 사용하여 이미 정해진 스타일을 변경해야한다면 네스팅을 이용하여 스타일링을 변경해야 함.

import React from 'react';
import styled from 'styled-components';
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';

const Main = () => {
  return (
    <Carousel>
      // slick 코드
    </Carousel>
  );
};

const Carousel = styled(Slider)`
    .slick-slide {
      // slick 커스텀 스타일
    }
`;

export default Main;

공통스타일

4.1 GlobalStyle

스타일드 컴포넌트에서는 createGlobalStyle 함수를 통해 전역에 적용하기 위한 스타일 컴포넌트 생성 가능.

  1. 전역 스타일 컴포넌트 만들기.
// src/styles/GlobalStyle.js

import React from 'react'
import { createGlobalStyle } from 'styled-components'

const GlobalStyle = createGlobalStyle`
  * {
    box-sizing: border-box;
    font-family: 'Noto Sans KR', sans-serif;
  }
`

export default GlobalStyle;
  1. index.js에 import
// index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import Router from './Router';
import GlobalStyle from './styles/GlobalStyle';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <ThemeProvider>
    <GlobalStyle />
    <Router />
  </ThemeProvider>
);

4.2 styled-reset

reset도 가능.

4.2.1 설치

npm install styled-reset

4.2.2 선언 방법

// src/styles/GlobalStyle.js

import React from 'react';
import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';

const GlobalStyle = createGlobalStyle`
  ${reset}

  * {
    box-sizing: border-box;
    font-family: 'Do Hyeon', sans-serif;
  }
`;

export default GlobalStyle;

4.3 ThemeProvider

스타일드 컴포넌트에서는 ThemeProvider를 통하여 전역으로 테마, JS변수 등을 공유하여 사용함.

// index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import GlobalStyle from './styles/GlobalStyle';
import theme from './styles/theme';
import Router from './Router';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <ThemeProvider theme={theme}>
    <GlobalStyle />
    <Router />
  </ThemeProvider>
);

4.3.1 theme

color, fontSize 등 공통 테마는 theme.js에서 선언 후 각 컴포에서 props로 받아 스타일 적용이 가능함.
ThemeProvider의 속성으로 넘기면 전역에서 사용 가능

// theme.js

const theme = {
  black: '#000000',
  white: '#FFFFFF',
  lightGrey: '#B0B0B0',
  middleGrey: '#717171',
  deepGrey: '#222222',
  hoverGrey: '#DBDBDB',
};

export default theme;

// App.js

import { Link } from 'react-router-dom';
import styled from 'styled-components';

const App = () => {
  return <Container>title</Container>;
};

const Container = styled.div`
  background-color: ${props => props.theme.lightGrey}
`;

전역 props 콘솔 찍어보면.

// App.js

const Container = styled.div`
  background-color: ${props => console.log(props)}
`;

// console.log(props)의 결과

props: {
    children: 'title',
    theme: {
      black: '#000000',
      white: '#FFFFFF',
      lightGrey: '#B0B0B0',
      middleGrey: '#717171',
      deepGrey: '#222222',
      hoverGrey: '#DBDBDB',
    },
  },

4.3.2 mixin

자주 사용하는 css 스타일은 variable.js파일 별도 관리
variable.js 는 theme과 varialbles를 Theme Provider에 같이 prop으로 합쳐서 전역에 사용하거나 사용하고자 하는 파일에서면 import해서 mixin을 사용할 수 있음.

// variables.js

import { css } from 'styled-components';

const variables = {
  flex: (direction = 'row', justify = 'center', align = 'center') =>`
    display: flex;
    flex-direction: ${direction};
    justify-content: ${justify};
    align-items: ${align};
  `,

  absoluteCenter: css`
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  `,
};

export default variables;
  1. ThemeProvider에서 prop으로 합쳐서 사용
// index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import GlobalStyle from './styles/GlobalStyle';
import theme from './styles/theme';
import variables from './styles/variables'
import Router from './Router';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <ThemeProvider theme={{ style: theme, variables }}>
    <GlobalStyle />
    <Router />
  </ThemeProvider>
);

사용예시)

// App.js

const App = () => {
  return (
    <Container>
      <Button>첫번째 버튼</Button>
      <Button>두번째 버튼</Button>
    </Container>
  );
};

const Container = styled.div`
  ${(props) => props.theme.variables.flexSet()} 
`;  // a

const Button = styled.button`
  background-color: ${(props) => props.theme.style.lightGrey};
`;

export default App;

기본 설정값 사용 ? -> flexSet()
바꾸고 싶엉 -> flexSet("","space-between","center")

  1. 각 컴포넌트에서 variables.js파일 import
// App.js

import styled from 'styled-components';
import variables from './styles/variables';

const App = () => {
  return (
    <Wrapper>
      <Button primary="pink">Pink Button</Button>
      <Button primary="Yellow">Yellow Button</Button>
    </Wrapper>
  );
};

const Wrapper = styled.div`
  ${variables.flex()}
`;

const Button = styled.button`
  margin: 20px;
  padding: 20px;
  border: none;
  background-color: ${(props) => props.primary};
  font-size: 20px;
`;

export default App;

4.4 글로벌 폰트

4.4.1 웹폰트

웹폰트는 임베드 코드 복사해서 html 파일에 코드 추가

// index.html

<head>
	<link rel="preconnect" href="https://fonts.googleapis.com" />
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
  <link
    href="https://fonts.googleapis.com/css2?family=Do+Hyeon&display=swap"
    rel="stylesheet"
  />
</head>

4.4.2 폰트파일

  1. styles 폴더 안에 폰트파일을 저장할 폴더를 생성하여 폰트파일을 넣어줌
src
└── styles
    ├── fonts
    │   └── DoHyeon-Regular.ttf
    ├── GlobalFont.js
    ├── GlobalStyle.js
    └── theme.js
  1. 스타일드 컴포넌트의 createGlobalStyle을 통해 글로벌 스타일 생성. 이 때 @font-face 사용하여 웹페이지에 적용 가능.
// src/styles/GlobalFont.js

import { createGlobalStyle } from 'styled-components';
import DoHyeon from './fonts/DoHyeon-Regular.ttf';

const GlobalFont = createGlobalStyle`
	@font-face { 
    font-family: 'Do Hyeon';
    src: url(${DoHyeon}) format('woff');
  }
`;

export default GlobalFont;
  1. 전역에서 사용하기 위해서는 아래와 같이 적용
// index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import GlobalStyle from './styles/GlobalStyle';
import GlobalFont from './styles/GlobalFont';
import color from './styles/theme';
import Router from './Router';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <ThemeProvider theme={theme}>
    <GlobalStyle />
    <GlobalFont />
	    <Router />
  </ThemeProvider>
);
profile
주먹구구식은 버리고 Why & How를 고민하며 프로그래밍 하는 개발자가 되자!

0개의 댓글