CSS-in-JS 관련 React 라이브러리 중 가장 인기 있는 Styled Component에 대하여 배워보았다.
Styled Component 는 React 의 컴포넌트 기반 개발 환경에서 스타일링을 위한 CSS의 성능 향상을 위해 생기게 되었다. 컴포넌트에 스타일을 직접적으로 선언할 수 있는 CSS-in-JS 라이브러리다. Styled Component 를 사용하면 기존 CSS 문법으로도 스타일 속성이 추가된 React 컴포넌트를 만들 수 있다.
기존에는 사스(sass)를 사용해서 스타일 요소를 관리했다. 리액트 컴포넌트로 예를 들자면 컴포넌트 이름과 동일한 CSS 클래스네임을 정의해서 컴포넌트의 클래스명으로 지정하는 방식이다. 이렇게 두 개의 파일 button.tsx, button.scss을 같은 폴더에서 관리하면 얼핏 괜찮은 구조라고 생각할 수 있는데 이게 그렇지가 않았다.
먼저는 컴포넌트 규모에 따라 사스 코드의 양이 변경되는데 서로 문법적으로 연결되어 있지 않는 것이 문제다. 가령 CSS 클래스만 변경하고 컴포넌트 코드를 고치지 않더라도 빌드는 성공한다. 변경된 스타일이 컴포넌트에 적용되지 않더라도 모를 수 있는 여지가 있다는 것이다. 이러한 부분을 보완한 스타일드 컴포넌트는 유동적으로 props를 내려 변경이 가능하며, 기존의 SASS의 장점인 Nesting, Mixin을 그대로 유지하여 스타일을 상속하거나 변수선언등이 편리하다.
기존 방식에서는 CSS 클래스 이름이 충돌할 가능성도 있다. 규칙을 정해 유일한 이름을 사용하면 되지만 범용적인 이름을 사용하는 경우도 이따금 발생한다. 가령 ".header" 클래스가 그러한데, 서비스 전체의 헤더, 혹은 컴포넌트의 헤더를 지칭하는 경우에 쓰인다. 같은 이름의 클래스 이름을 사용하는 순간 CSS 중첩 구조에 따라 정의한 순서대로 영향을 받게된다. 이 외에도 공식문서에 styled component를 사용함으로써 얻을 수 있는 장점이 나열되어져 있다.
문법은 간단하다. 리액트에서 컴포넌트를 만들듯이 tag의 속성을 정의하고 백틱 안에 기존 CSS 속성들을 나열해주면 된다.
import styled from "styled-components"; //라이브러리 import 해오기
// <h1> 태그를 렌더링 할 title component를 만들기
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
// <section> 태그를 렌더링 할 Wrapper component를 만들기
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
export default function App() {
// 일반적으로 컴포넌트를 사용하는 것처럼 Title과 Wrapper를 사용하면 된다
return (
<Wrapper>
<Title>Hello World!</Title>
</Wrapper>
);
}
생성된 컴포넌트의 props를 받아서 스타일을 선택적으로 적용할 수 있다.
// Button component
...
background: ${(props) => (props.primary ? "palevioletred" : "white")};
color: ${(props) => (props.primary ? "white" : "palevioletred")};
...
// App component
...
<Button>Normal</Button>
<Button primary>Primary</Button> //props(=primary)를 넘겨준다
...
컴포넌트에 props 로 스타일 속성이 전달된다면 해당 컴포넌트는 props 로 전달된 속성을 우선 적용하며, 전달되는 속성이 없다면 기본으로 설정된 속성을 적용한다(아래 예제에서 기본 설정 속성은 red). 이는 Styled Component 가 개발자에 의해 설정된 속성과 기본 속성을 구분할 수 있기 때문이다.
import styled from "styled-components";
// Styled Component로 만들어진 Input 컴포넌트
const Input = styled.input`
padding: 0.5em;
margin: 0.5em;
color: ${(props) => props.inputColor || "red"}; //props속성에 inputColor가 있다면? 그 컬러로 텍스트 색깔 설정, props속성에 inputColor가 없다면? red로
background: papayawhip;
border: none;
border-radius: 3px;
`;
export default function App() {
return (
<div>
{/* 아래 Input 컴포넌트는 styled component인 Input 컴포넌트에 지정된 inputColor(red)가 적용되었습니다. */}
<Input defaultValue="김코딩" type="text" />
{/* 아래 Input 컴포넌트는 props로 전달된 커스텀 inputColor(blue)가 적용되었습니다. */}
<Input defaultValue="박해커" type="text" inputColor="blue" />
</div>
);
}
아래 예시처럼 Button의 스타일 속성을 RedButton이 물려받아 사용할 수 있다. 이때에는 상속받고자 하는 스타일 속성을 지닌 컴포넌트를 styled() 로 감싼 뒤, 변경하고 싶은 속성만 새로 정의해 주면 기존 속성을 확장하여 사용할 수 있다.
const Button = styled.button`
padding: 6px 12px;
color: white;
font-size: 16px;
border: none;
border-radius: 4px;
background-color: #74b9ff;
:hover {
background-color: #99c6f5;
}
`;
const RedButton = styled(Button)` //아래 두 속성만 제외하고 나머지 속성을 모두 물려받는다
background-color: #f53e3e;
:hover {
background-color: #ff7268;
}
`;