icon
5장 : 스타일링과 CSS

Styled-components 기초


우리는 CSS 모듈을 통해 클래스 이름 충돌 문제를 해결하고 컴포넌트 단위의 스타일링을 구현하는 방법을 배웠습니다. 이제 5장 "스타일링과 CSS"의 세 번째 방법으로, CSS-in-JS의 대표적인 라이브러리 중 하나인 Styled-components를 소개합니다.

Styled-components는 자바스크립트 코드 내에서 CSS를 작성하고, 이를 컴포넌트에 직접 연결하여 사용하는 방식입니다. 이 방식은 스타일을 컴포넌트 로직과 함께 한 파일에 묶어 관리함으로써, 스타일링을 '컴포넌트의 일부'로 간주하는 리액트의 철학과 매우 잘 맞아떨어집니다.


CSS-in-JS란?

CSS-in-JS는 말 그대로 JavaScript 코드 안에 CSS를 작성하는 방식을 통칭합니다. 기존에는 CSS 파일을 별도로 분리하여 관리했지만, CSS-in-JS는 컴포넌트 로직과 스타일 로직을 하나의 JavaScript 파일 안에서 함께 작성합니다.

Styled-components의 핵심 아이디어

  • 컴포넌트 기반 스타일링: 스타일이 적용된 리액트 컴포넌트를 생성합니다.
  • 고유한 클래스 이름 자동 생성: CSS 모듈처럼 자동으로 고유한 해시 클래스 이름을 생성하여 클래스 이름 충돌을 방지합니다.
  • 동적 스타일링 용이: JavaScript의 모든 기능을 활용하여 props나 state에 따라 스타일을 매우 유연하고 강력하게 변경할 수 있습니다.
  • 스코프된 스타일: 생성된 스타일은 해당 컴포넌트에만 영향을 미치므로 전역 오염 걱정이 없습니다.

Styled-components 설치

Styled-components를 사용하기 위해서는 먼저 라이브러리를 설치해야 합니다. 터미널에서 다음 명령어를 실행하세요.

npm install styled-components
# 또는
yarn add styled-components

Styled-components 기본 사용법

Styled-components는 태그드 템플릿 리터럴(Tagged Template Literals) 문법을 사용하여 스타일이 적용된 컴포넌트를 생성합니다.

import styled from 'styled-components'; // styled 객체 임포트

// 1. styled.{HTML 태그} 백틱(``) 안에 CSS 작성
const StyledButton = styled.button`
  background-color: #61dafb;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 1em;
  transition: all 0.3s ease-in-out;

  &:hover { /* 가상 클래스도 바로 사용 가능 */
    background-color: #21a1f1;
    transform: translateY(-2px);
  }

  &:active {
    transform: translateY(0);
  }
`;

function MyComponent() {
  return (
    <StyledButton>클릭하세요</StyledButton> // 2. 스타일링된 컴포넌트 사용
  );
}

예제: 기본적인 스타일링 컴포넌트 만들기

src/components/StyledComponentsBasic.js 파일을 생성하고 다음 코드를 작성하세요.

src/components/StyledComponentsBasic.js
// src/components/StyledComponentsBasic.js
import React from 'react';
import styled from 'styled-components'; // styled-components 임포트

// 1. 스타일이 적용된 <Container> 컴포넌트 생성
const Container = styled.div`
  background-color: #f0f8ff; /* 연한 하늘색 배경 */
  padding: 30px;
  border-radius: 10px;
  box-shadow: 0 5px 15px rgba(0,0,0,0.1);
  text-align: center;
  margin-bottom: 30px;
`;

// 2. 스타일이 적용된 <Title> 컴포넌트 생성
const Title = styled.h2`
  color: #1e90ff; /* 진한 파란색 */
  font-size: 2.5em;
  margin-bottom: 15px;
  text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
`;

// 3. 스타일이 적용된 <Paragraph> 컴포넌트 생성
const Paragraph = styled.p`
  color: #4682b4; /* 중간 파란색 */
  font-size: 1.2em;
  line-height: 1.7;
  margin-bottom: 20px;
`;

// 4. 스타일이 적용된 <StyledButton> 컴포넌트 생성
const StyledButton = styled.button`
  background-color: #007bff;
  color: white;
  padding: 12px 25px;
  border: none;
  border-radius: 7px;
  cursor: pointer;
  font-size: 1.1em;
  font-weight: bold;
  transition: background-color 0.3s ease, transform 0.2s ease;

  &:hover { /* 가상 클래스 */
    background-color: #0056b3;
    transform: translateY(-2px);
  }

  &:active {
    transform: translateY(0);
  }
`;

function StyledComponentsBasic() {
  return (
    <Container> {/* 생성한 Styled 컴포넌트 사용 */}
      <Title>Styled-components 기초 예제</Title>
      <Paragraph>
        이것은 styled-components로 스타일링된 단락입니다.
        스타일이 컴포넌트 자체에 포함되어 있습니다.
      </Paragraph>
      <StyledButton>Styled 버튼</StyledButton>
    </Container>
  );
}

export default StyledComponentsBasic;

App.js에서 렌더링

App.js 파일을 수정하여 StyledComponentsBasic 컴포넌트를 렌더링하세요.

src/App.js
// src/App.js (수정)
import React from 'react';
import './index.css'; // 전역 스타일 유지
import StyledComponentsBasic from './components/StyledComponentsBasic';
// import CssModulesExample from './components/CssModulesExample'; // 필요 없으면 주석 처리 또는 삭제

function App() {
  return (
    <div className="App">
      <h1>Styled-components 학습</h1>
      <StyledComponentsBasic />
    </div>
  );
}

export default App;

브라우저에서 개발자 도구(F12)를 열어 엘리먼트 탭을 확인해 보세요. 각 HTML 요소에 sc-xxx와 같은 프리픽스와 고유한 해시값이 붙은 클래스 이름이 자동으로 생성되어 있는 것을 볼 수 있습니다.


Props를 이용한 동적 스타일링

Styled-components의 가장 큰 장점 중 하나는 props를 이용하여 스타일을 동적으로 변경할 수 있다는 것입니다. 태그드 템플릿 리터럴 내에서 JavaScript 코드를 삽입할 수 있는 것처럼, props를 인자로 받는 함수를 작성하여 동적인 스타일을 적용할 수 있습니다.

src/components/DynamicStyledButton.js
// src/components/DynamicStyledButton.js
import React from 'react';
import styled from 'styled-components';

// props에 따라 색상이 변하는 버튼
const DynamicButton = styled.button`
  background-color: ${props => props.primary ? '#007bff' : '#6c757d'}; /* (1) props.primary에 따라 배경색 변경 */
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 1em;
  margin: 5px;
  transition: background-color 0.3s ease;

  &:hover {
    background-color: ${props => props.primary ? '#0056b3' : '#5a6268'};
  }
`;

// props에 따라 크기가 변하는 텍스트
const ResizableText = styled.p`
  font-size: ${props => props.size || '1em'}; /* (2) props.size에 따라 폰트 크기 변경 */
  color: ${props => props.color || '#333'}; /* (3) props.color에 따라 색상 변경 */
  margin-top: 15px;
`;


function DynamicStyledComponents() {
  return (
    <div style={{ textAlign: 'center', margin: '20px', padding: '20px', border: '1px dashed #ccc', borderRadius: '8px' }}>
      <h2>동적 스타일링 예제</h2>
      <DynamicButton primary>기본 버튼</DynamicButton> {/* primary prop 전달 */}
      <DynamicButton>보조 버튼</DynamicButton> {/* primary prop 없음 */}

      <ResizableText size="1.5em" color="#d9534f">크고 빨간 텍스트</ResizableText>
      <ResizableText size="0.8em" color="#5cb85c">작고 초록 텍스트</ResizableText>
    </div>
  );
}

export default DynamicStyledComponents;

App.jsDynamicStyledComponents 컴포넌트를 추가하고 실행해 보세요. primary, size, color와 같은 props를 전달하여 컴포넌트의 스타일이 동적으로 변경되는 것을 확인할 수 있습니다. 이는 인라인 스타일링과 유사하게 강력한 동적 스타일링 기능을 제공하면서도, CSS의 모든 기능을 활용할 수 있다는 장점을 가집니다.


as prop을 이용한 태그 변경

Styled-components로 생성된 컴포넌트는 as prop을 사용하여 렌더링될 HTML 태그를 변경할 수 있습니다. 이는 동일한 스타일을 유지하면서 다른 시맨틱 태그를 사용해야 할 때 유용합니다.

src/components/AsPropExample.js
// src/components/AsPropExample.js
import React from 'react';
import styled from 'styled-components';

const ButtonLike = styled.button`
  background-color: #ffc107;
  color: #333;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 1em;
  margin: 5px;
  transition: background-color 0.3s ease;

  &:hover {
    background-color: #e0a800;
  }
`;

function AsPropExample() {
  return (
    <div style={{ textAlign: 'center', margin: '20px', padding: '20px', border: '1px dashed #ccc', borderRadius: '8px' }}>
      <h2>'as' prop 예제</h2>
      <ButtonLike>나는 button 태그입니다</ButtonLike>
      {/* ButtonLike 컴포넌트의 스타일은 유지하되, 렌더링되는 HTML 태그는 <a>로 변경 */}
      <ButtonLike as="a" href="#" onClick={(e) => e.preventDefault()}>나는 a 태그입니다</ButtonLike>
      {/* ButtonLike 컴포넌트의 스타일은 유지하되, 렌더링되는 HTML 태그는 <div>로 변경 */}
      <ButtonLike as="div">나는 div 태그입니다</ButtonLike>
    </div>
  );
}

export default AsPropExample;

App.jsAsPropExample 컴포넌트를 추가하여 실행해 보세요. 모두 동일한 스타일을 가지고 있지만, 개발자 도구에서 실제 HTML 태그가 다르게 렌더링되는 것을 확인할 수 있습니다.


다른 컴포넌트 확장하기

기존에 스타일링된 컴포넌트의 스타일을 상속받아 새로운 스타일을 추가할 수 있습니다. Styled-components v4부터는 styled(기존컴포넌트) 문법을 사용하는 것이 권장됩니다.

src/components/ExtendedStyledComponent.js
// src/components/ExtendedStyledComponent.js
import React from 'react';
import styled from 'styled-components';

const BaseButton = styled.button`
  padding: 10px 20px;
  font-size: 1em;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.3s ease, color 0.3s ease;
`;

// BaseButton의 스타일을 상속받아 새로운 스타일 추가
const PrimaryButton = styled(BaseButton)`
  background-color: #28a745;
  color: white;
  border: 1px solid #28a745;

  &:hover {
    background-color: #218838;
    border-color: #218838;
  }
`;

// BaseButton의 스타일을 상속받아 또 다른 스타일 추가
const DangerButton = styled(BaseButton)`
  background-color: #dc3545;
  color: white;
  border: 1px solid #dc3545;

  &:hover {
    background-color: #c82333;
    border-color: #c82333;
  }
`;

function ExtendedStyledComponent() {
  return (
    <div style={{ textAlign: 'center', margin: '20px', padding: '20px', border: '1px dashed #ccc', borderRadius: '8px' }}>
      <h2>컴포넌트 확장 예제</h2>
      <BaseButton>기본 버튼</BaseButton>
      <PrimaryButton style={{ marginLeft: '10px' }}>확장된 기본 버튼</PrimaryButton>
      <DangerButton style={{ marginLeft: '10px' }}>확장된 위험 버튼</DangerButton>
    </div>
  );
}

export default ExtendedStyledComponent;

App.jsExtendedStyledComponent 컴포넌트를 추가하여 실행해 보세요. BaseButton의 기본 스타일을 재사용하면서 각각 다른 색상의 버튼을 효율적으로 생성할 수 있습니다.


"Styled-components 기초"는 여기까지입니다. 이 장에서는 Styled-components의 기본적인 설치와 사용법, props를 이용한 동적 스타일링, as prop을 이용한 태그 변경, 그리고 기존 컴포넌트를 확장하는 방법까지 상세하게 다루었습니다.

Styled-components는 스타일을 컴포넌트 로직과 함께 관리하고, JavaScript의 강력한 기능을 활용하여 동적인 스타일링을 매우 유연하게 구현할 수 있게 해줍니다. 이는 컴포넌트 중심의 리액트 개발에 매우 적합한 방식이며, 많은 현대 리액트 프로젝트에서 선호되고 있습니다.

다음 장에서는 CSS-in-JS의 또 다른 주요 기능인 테마(Theming)전역 스타일(Global Styles) 에 대해 알아보겠습니다.