styled-components

@bbearcookie · April 11, 2023 · 5 min read

리액트 라이브러리로 개발할 때 컴포넌트의 스타일링을 위해서는 크게 CSS-in-CSS 방식과 CSS-in-JS 방식이 있다.
styled-componentsCSS-in-JS 방식으로 컴포넌트의 스타일을 위해서 따로 스타일 시트 파일을 작성하는 것이 아니라, 자바스크립트 파일 내에서 작성해주는 방식인데 리액트로 개발하면서 컴포넌트들의 동적인 props를 가지고 스타일을 자유 자재로 변경하고 싶은 경우에 쉽게 사용할 수 있어 유용하다고 생각한다.

정확한 사용 방법을 몰라서 헤맸던 몇 가지 기능이 있었는데, 이를 이번에 정리해보고자 한다.

스타일 확장

스타일 컴포넌트가 아닌 일반 리액트 컴포넌트에 대해서도 스타일 확장이 가능하다.
PaddedButton을 보면 일반 컴포넌트인 Button에 대해서 스타일을 확장 하고 있다.
다만 중요한 점은 PaddedButton 을 사용할 때 Button 내부에 className 이 props로 전달되는데, 이걸 반드시 일반 컴포넌트가 반환하는 요소의 className 으로 전달해줘야 한다는 것이다.
그렇지 않으면 스타일이 정상적으로 적용되지 않는다.

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

interface Props {
  className?: string;
  children?: React.ReactNode;
}

function Button({ className, children }: Props) {
  return <button className={className}>{children}</button>;
}

export const PaddedButton = styled(Button)`
  padding: 1.5em;
`;

export const RedButton = styled(PaddedButton)`
  background-color: red;
`;

export const YellowButton = styled(PaddedButton)`
  background-color: yellow;
`;

컴포넌트 지정

CSS에서 선택자를 지정하는 것처럼, 스타일 컴포넌트를 대상으로 선택자를 지정하는 것처럼 사용할 수 있다.
아래 코드를 보면 StyledCard 내부의 PaddedButton 컴포넌트를 대상으로 background-color 속성을 지정해주고 있다.

그리고 믹스인과 같은 기능은 border 처럼 css 함수를 이용해서 정의하고, 이를 스타일 컴포넌트 내부에서 가져와 사용하는 방법으로 사용할 수 있다.

또한, 스타일 컴포넌트가 받는 props의 타입은 제네릭으로 지정해주면 된다.

import React from 'react';
import styled, { css } from 'styled-components';
import { PaddedButton } from './Button';

interface Props {
  children?: React.ReactNode;
}

function Card({ children }: Props) {
  return (
    <StyledCard buttonColor="pink">
      {children}
      <PaddedButton>카드 내부의 버튼</PaddedButton>
    </StyledCard>
  );
}

export default Card;

const border = css`
  border: 1px solid red;
  border-radius: 5px;
`;

const StyledCard = styled.div<{ buttonColor: string }>`
  ${border}

  ${PaddedButton} {
    background-color: ${p => p.buttonColor};
  }
`;

css prop

Styled-component 버전 4 부터는 css prop 기능을 이용할 수 있다.
이 기능은 간단한 스타일 지정을 위해서 styled 함수를 호출하여 새로운 스타일 컴포넌트를 만드는 번거로운 과정을 거치지 않고도 스타일을 지정해줄 수 있는 기능이다.

div, span 같은 기본적인 태그 요소나 스타일 컴포넌트를 대상으로 css prop을 전달해줄 수 있다.

import { PaddedButton, RedButton, YellowButton } from './component/Button';
import Card from './component/Card';

function App() {
  return (
    <div className="App">
      <PaddedButton>버튼</PaddedButton>
      <RedButton>빨간 버튼</RedButton>
      <YellowButton>노란 버튼</YellowButton>
      <PaddedButton css={{ backgroundColor: 'green' }}>초록 버튼</PaddedButton>
      <Card css={{ backgroundColor: 'green' }}>내용...</Card>
    </div>
  );
}

export default App;

다만 이 기능을 사용하려면 몇 가지 설정을 해야한다.

바벨 설정

babel-plugin-styled-components 를 설치한다.

npm install --save-dev babel-plugin-styled-components

그리고 바벨에 아래처럼 설정해준다.

{
  "plugins": ["babel-plugin-styled-components"]
}

만약 craco를 사용한다면 craco.config.js 에 다음과 같이 바벨 설정을 한다.

module.exports = {
  babel: {
    plugins: ['babel-plugin-styled-components'],
  },
};

타입 import

타입스크립트를 사용하는 경우에는 cssprop 의 타입을 한 번 import 해줘야 한다.
이는 프로젝트에서 한 번만 해주면 된다. 예를 들어 index.tsx 에 다음 구문을 작성한다.

import * as types from 'styled-components/cssprop';
@bbearcookie
Frontend Developer