
저는 React 개발을 위해 팀에서 사용하는 Styled-Components에 대해 공부하게 되었습니다.
CSS는 프로젝트가 커질수록 관리하기 어려운 경우가 많습니다.
전역으로 스타일이 흩어져 있거나, 클래스명이 충돌하거나, 재사용하기 힘든 문제가 자주 발생합니다.
이런 문제들을 해결하기 위해 등장한 개념이 CSS-in-JS입니다.
이번 글에서는 이 개념을 간단히 소개하고, 그 중에서도 많이 쓰이는 라이브러리인 Styled-Components에 대해 알아보겠습니다.
CSS-in-JS
CSS를 자바스크립트 파일 안에서 작성하는 방식
이 방식을 사용하면 스타일과 컴포넌트를 하나의 단위로 묶을 수 있어서, 유지보수성과 재사용성이 높아집니다.
또한 전역 네임스페이스 문제를 피할 수 있고, props나 state와 같이 동적인 값에 따라 스타일을 변경하기도 쉽습니다.
Styled-Components
React에서 스타일을 관리하는 전통적인 방식은 CSS 파일을 따로 작성하는 것이지만,
프로젝트가 커질수록 클래스명 충돌이나 전역 스타일 오염 같은 문제가 생기기 쉽습니다.
이러한 한계를 보완하기 위해 나온 개념이 CSS-in-JS이고, 그중 대표적인 도구가 바로 Styled-Components입니다.
이제 Styled-Components에 대해 제대로 알아보겠습니다.
1) Styled-Components란?
CSS-in-JS 방식으로 스타일을 작성할 수 있게 해주는 라이브러리
Styled-Components는 CSS-in-JS 라이브러리 중 하나로, React 개발에서 가장 많이 사용되는 도구 중 하나입니다.
컴포넌트 단위로 스타일을 정의할 수 있고, 작성한 스타일은 바로 React 컴포넌트처럼 사용할 수 있습니다.
따라서 디자인과 로직이 밀접하게 연결되어, 스타일을 더 직관적으로 다룰 수 있습니다.
2) Styled-Components의 장점
- 스타일의 캡슐화 : 컴포넌트별로 스타일이 분리되어 전역 충돌 막기 가능
- 동적 스타일링 : props 값을 받아 조건에 따라 스타일 변경 가능
- CSS 문법 그대로 사용 : 기존 CSS를 크게 변형하지 않고 사용 가능
- 자동 벤더 프리픽스 : 브라우저 호환성을 위해 별도의 설정 없이 접두사가 자동으로 붙음
- 유지보수 용이 : 코드와 스타일이 한 파일 안에서 관리되므로 구조 단순화
위와 같은 장점 때문에, Styled-Components는 많은 프로젝트에서 널리 사용됩니다.
설치 방법
먼저 VS Code에서 설치한 React 프로젝트를 열어 터미널을 실행합니다.
이후 아래 명령어를 입력하면 Styled-Components를 설치할 수 있습니다.
npm install styled-components
스타일 적용 방식 비교
React에서 스타일을 적용하는 기본 방법은 크게 세 가지가 있습니다.
인라인, CSS 파일, Styled-Components에 대해 아래에서 차례대로 살펴보겠습니다.
1) 인라인 스타일 방식
export default function App() {
return (
<button
style={{
backgroundColor: "blue",
color: "white",
borderRadius: "3px",
padding: "0.5rem 1rem"
}}
>
클릭
</button>
);
}
빠르게 작성이 가능하며, 별도로 파일이 필요하지 않습니다.
그러나, CSS 문법을 그대로 쓸 수 없고, 중복 스타일에 대한 관리가 어렵습니다.
2) CSS 파일 + className 방식
App.css
.button {
background-color: blue;
color: white;
border-radius: 3px;
padding: 0.5rem 1rem;
}
App.tsx
import "./App.css";
export default function App() {
return <button className="button">클릭</button>;
}
익숙한 CSS 문법 그대로 사용이 가능하지만, 전역 클래스명 충돌에 대한 위험이 있습니다.
3) Styled-Components 방식 (CSS-in-JS)
import styled from "styled-components";
const Button = styled.button`
background: blue;
color: white;
border-radius: 3px;
padding: 0.5rem 1rem;
`;
export default function App() {
return <Button>클릭</Button>;
}
위 코드에서 styled.button으로 정의한 부분은 일반 CSS 문법과 거의 동일합니다.
작성된 Button 스타일은 React 컴포넌트처럼 사용이 가능하며, 스타일이 캡슐화되어 다른 곳에 영향을 주지 않습니다.
따라서 Styled-Components를 적용하면 코드가 좀 더 깔끔해지고 가독성도 좋아집니다.
또한, 작성한 코드를 브라우저 개발자 도구에서 확인해보면 실제로는 아래처럼 변환됩니다.
<button class="sc-bcXHqe iEwLsm">클릭</button>
여기서 sc-bcXHqe와 iEwLsm 같은 클래스명이 자동으로 붙는데,
이는Styled-Components가 내부적으로 해시 기반으로 생성하는 고유한 식별자입니다.
덕분에 매번 충돌 없는 클래스명이 적용되어, 직접 클래스명을 관리할 필요가 없고 전역 스타일 충돌 문제도 방지할 수 있습니다.
사용 방법
Styled-Components는 단순히 스타일을 작성하는 것뿐 아니라 다양한 기능을 제공합니다.
그중에서 많이 활용되는 기능인 props, 스타일 상속, 태그 변경, 테마 적용, 글로벌 스타일을 차례대로 살펴보겠습니다.
1) props 활용
props 값을 받아 조건에 따라 스타일을 다르게 적용할 수 있습니다.
import styled from "styled-components";
const Button = styled.button<{ primary?: boolean }>`
background: ${(props) => (props.primary ? "blue" : "gray")};
color: white;
border-radius: 3px;
padding: 0.5rem 1rem;
`;
export default function App() {
return (
<>
<Button>기본 버튼</Button>
<Button primary>Primary 버튼</Button>
</>
);
}
primary라는 props를 넘기면, 결과에 따라 버튼 색상이 바뀌도록 설정했습니다.
2) 스타일 상속
이미 정의한 컴포넌트를 기반으로 스타일을 확장할 수 있습니다.
기존 Button 스타일을 재사용하면서 일부 속성만 덮어쓸 수 있습니다.
import styled from "styled-components";
const Button = styled.button`
background: blue;
color: white;
border-radius: 3px;
padding: 0.5rem 1rem;
`;
const DangerButton = styled(Button)`
background: red; /* 덮어쓰기 */
border: 2px solid darkred; /* 추가 */
font-weight: bold; /* 추가 */
`;
export default function App() {
return (
<>
<Button>기본 버튼</Button>
<DangerButton>위험 버튼</DangerButton>
</>
);
}
위의 코드를 보면, DangerButton 스타일은 styled(Button)을 통해 Button 스타일을 재사용한다는 뜻입니다.
DangerButton 스타일은 기존 Button 스타일에 정의된 속성들(background, color, padding)을 기본적으로 상속합니다.
DangerButton에서 background: red;를 정의했으므로, 원래 blue였던 부분이 빨간색으로 덮어쓰기 됩니다.
즉, background 속성은 Button → DangerButton 순으로 적용되어 최종적으로는 빨간색이 됩니다.
또한 DangerButton 스타일에서 border, font-weight와 같이 Button 스타일에 없던 속성을 추가할 수 있습니다.
이렇게 하면 기본 스타일 + 덮어쓴 속성 + 추가 속성이 모두 적용됩니다.
3) 태그 변경
.withComponent를 사용하면 동일한 스타일을 유지한 채 태그만 변경할 수 있습니다.
import styled from "styled-components";
const Title = styled.h1`
color: blue;
font-size: 2rem;
`;
const TitleAsSpan = Title.withComponent("span");
export default function App() {
return (
<>
<Title>제목 (h1)</Title>
<TitleAsSpan>제목 (span)</TitleAsSpan>
</>
);
}
위의 코드를 보면, h1 태그에 대해 적용한 Title 스타일을 span 태그로 바꿔 사용하고 싶을 때
.withComponent를 이용할 수 있습니다.
동일한 스타일이라면 h1 태그뿐 아니라 span 태그로도 쉽게 재사용할 수 있는 것입니다.
4) 테마 적용
ThemeProvider를 사용하면 색상, 폰트 크기 등을 전역적으로 관리할 수 있습니다.
import styled, { ThemeProvider } from "styled-components";
const theme = {
colors: {
primary: "blue",
secondary: "gray",
},
};
const Button = styled.button`
background: ${(props) => props.theme.colors.primary};
color: white;
border-radius: 3px;
padding: 0.5rem 1rem;
`;
export default function App() {
return (
<ThemeProvider theme={theme}>
<Button>테마 버튼</Button>
</ThemeProvider>
);
}
위의 코드에서 theme 객체에 색상 팔레트와 폰트 크기를 정의해두면,
모든 컴포넌트에서 props를 통해 전역 값을 불러올 수 있다는 것을 확인해볼 수 있습니다.
이렇게 하면 디자인 시스템을 쉽고 일관성 있게 유지할 수 있습니다.
5) 글로벌 스타일
createGlobalStyle을 이용하면 reset CSS나 공통 스타일을 프로젝트 전체에 적용할 수 있습니다.
글로벌 스타일을 한 번만 정의해두면, 프로젝트 전반에 걸쳐 일관된 기본 스타일을 유지할 수 있습니다.
import styled, { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
font-family: Arial, sans-serif;
background: #f5f5f5;
}
h1 {
color: blue;
}
`;
const RedTitle = styled.h1`
color: red;
`;
export default function App() {
return (
<>
<GlobalStyle /> {/* 여기서 한 번만 호출 */}
<h1>파란색 제목 (GlobalStyle)</h1>
<RedTitle>빨간색 제목 (개별 스타일)</RedTitle>
</>
);
}
위의 코드를 보면, App 최상단(보통 <App /> 안)에 <GlobalStyle />로 한 번만 호출하면,
그 뒤에 렌더링되는 모든 HTML 요소에 공통 스타일이 적용됩니다.
공통 스타일이 기본값처럼 깔리지만, 이후 개별 컴포넌트에서 더 구체적으로 정의하면 해당 스타일을 주면 덮어쓸 수도 있습니다.
따라서 GlobalStyle 스타일에서 h1 태그의 색을 파란색으로 지정했더라도,
RedTitle이라는 별도 스타일을 정의하면 그 스타일이 덮어쓰여 빨간색으로 표시됩니다.
이것은 CSS는 우선순위 규칙(Cascade)때문입니다.
즉, GlobalStyle 스타일은 기본값 역할을 하고, 필요할 때 개별 컴포넌트 스타일로 덮어씌우면 됩니다.
정리하며
Styled-Components는 React 개발에서 디자인과 로직을 자연스럽게 연결해주는 도구였습니다.
CSS 관리의 어려움을 줄이고, 컴포넌트 중심으로 직관적인 스타일링을 가능하게 합니다.
프로젝트의 성격과 팀의 스타일에 맞게 적용한다면,
효율적이고 깔끔한 UI 개발에 큰 도움이 될 것이라고 생각합니다.