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
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 (수정)
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
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.js
에 DynamicStyledComponents
컴포넌트를 추가하고 실행해 보세요. primary
, size
, color
와 같은 props를 전달하여 컴포넌트의 스타일이 동적으로 변경되는 것을 확인할 수 있습니다. 이는 인라인 스타일링과 유사하게 강력한 동적 스타일링 기능을 제공하면서도, CSS의 모든 기능을 활용할 수 있다는 장점을 가집니다.
as
prop을 이용한 태그 변경
Styled-components로 생성된 컴포넌트는 as
prop을 사용하여 렌더링될 HTML 태그를 변경할 수 있습니다. 이는 동일한 스타일을 유지하면서 다른 시맨틱 태그를 사용해야 할 때 유용합니다.
// 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.js
에 AsPropExample
컴포넌트를 추가하여 실행해 보세요. 모두 동일한 스타일을 가지고 있지만, 개발자 도구에서 실제 HTML 태그가 다르게 렌더링되는 것을 확인할 수 있습니다.
다른 컴포넌트 확장하기
기존에 스타일링된 컴포넌트의 스타일을 상속받아 새로운 스타일을 추가할 수 있습니다. Styled-components v4부터는 styled(기존컴포넌트)
문법을 사용하는 것이 권장됩니다.
// 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.js
에 ExtendedStyledComponent
컴포넌트를 추가하여 실행해 보세요. BaseButton
의 기본 스타일을 재사용하면서 각각 다른 색상의 버튼을 효율적으로 생성할 수 있습니다.
"Styled-components 기초"는 여기까지입니다. 이 장에서는 Styled-components의 기본적인 설치와 사용법, props를 이용한 동적 스타일링, as
prop을 이용한 태그 변경, 그리고 기존 컴포넌트를 확장하는 방법까지 상세하게 다루었습니다.
Styled-components는 스타일을 컴포넌트 로직과 함께 관리하고, JavaScript의 강력한 기능을 활용하여 동적인 스타일링을 매우 유연하게 구현할 수 있게 해줍니다. 이는 컴포넌트 중심의 리액트 개발에 매우 적합한 방식이며, 많은 현대 리액트 프로젝트에서 선호되고 있습니다.
다음 장에서는 CSS-in-JS의 또 다른 주요 기능인 테마(Theming) 와 전역 스타일(Global Styles) 에 대해 알아보겠습니다.