React에는 여러 방법을 통해 CSS를 적용할 수 있다(참고 - React에 CSS를 적용하는 여러 방법). 그 중에서도 개인적으로 가장 좋다고 생각되는 Styled-Components의 여러 사용 방법에 대해 알아보자.
Styled Components는 NPM(Node Package Manager)를 통해 관리되는 패키지이기 때문에, 간단한 명령어를 통해 설치할 수 있다.
$ npm i styled-components
설치가 성공적으로 이루어졌다면, package.json
파일에 디펜던시가 추가되어 있을 것이다.
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "5.0.0",
"styled-components": "^5.3.3",
}
Styled Components를 사용하기 위해서는 가장 먼저, 아까 설치한 styled-components
패키지에서 styled
를 import 해야 한다.
import styled from "styled-components";
기본적으로 html의 모든 태그들에 스타일을 적용할 수 있다. 적용 방법은 styled.tagName
과 같이 작성한 뒤, 적용하고자 하는 CSS 스타일을 작성하면 된다.
import styled from "styled-components";
const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 15vh;
`;
const BoxOne = styled.div`
background-color: #cf6a87;
width: 100px;
height: 100px;
`;
const BoxTwo = styled.div`
background-color: #574b90;
width: 100px;
height: 100px;
`;
const App = () => {
return (
<Wrapper>
<BoxOne />
<BoxTwo />
</Wrapper>
);
};
Styled Components를 이용하여 박스 두 개를 성공적으로 화면에 나타냈는데, 뭔가가 아쉽다. BoxOne
, BoxTwo
는 각각 배경색을 제외하고는 중복된 코드를 가지고 있기 때문이다.
다행히도 Styled Components에서는 props를 통해 각각의 컴포넌트마다 원하는 속성을 적용할 수 있게 해준다.
... 생략
const Box = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
`;
const App = () => {
return (
<Wrapper>
<Box bgColor={"#cf6a87"} />
<Box bgColor={"#574b90"} />
</Wrapper>
);
};
BoxOne
, BoxTwo
두 가지 컴포넌트를 Box
라는 하나의 컴포넌트로 통합하고 bgColor라는 속성을 통해 각각 배경색을 지정해주었다. 처음의 코드보다 재사용성이 크게 증가했다는 것을 한 눈에 봐도 느낄 수 있을 것이다.
이번에는 Box
컴포넌트와 같은 크기를 가진 Circle
컴포넌트를 만들어보자!
const Circle = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
border-radius: 50%;
`;
border-radius 속성을 제외하고는 Box
컴포넌트와 다를게 없다. Styled Components에서는 이러한 코드의 중복을 막기 위해서 html의 태그 뿐만 아니라, Styled Components를 통해 만든 컴포넌트도 다시 정의하여 사용할 수 있다!
차이점이라면 styled(ComponentName)
와 같이 컴포넌트 명을 괄호 안에 넣어줘야 한다는 것 하나뿐이다.
const Circle = styled(Box)`
border-radius: 50%;
`
const App = () => {
return (
<Wrapper>
<Box bgColor={"#cf6a87"} />
<Box bgColor={"#574b90"} />
<Circle bgColor={"black"} />
</Wrapper>
);
};
Box
가 너무 예뻐서 다른 곳에서 버튼으로도 사용하고 싶어질 수가 있다..! 하지만 Box
는 div로 정의되어 있고, 원래의 Box
와 동시에 사용하면서 중복되는 코드도 만들고 싶지 않다.
그럴 때는 아주 간단하게 컴포넌트의 태그에 as
속성을 추가해주면 된다.
const App = () => {
return (
<Wrapper>
<Box bgColor={"#cf6a87"} />
<Box as="button" bgColor={"#574b90"} />
<Circle bgColor={"black"} />
</Wrapper>
);
};
as
속성만 추가했는데 성공적으로 button 태그로 바뀐 것을 확인할 수 있다.
required 속성을 가진 input 태그가 여러 개 필요할 경우, 각각의 태그마다 required 속성을 추가하는 것은 매우 번거롭고 귀찮다. 만약 수정할 일이 생긴다면, 하나씩 변경하는 것은 더더욱 귀찮을 것이다.
Styled Components에서는 html 태그의 속성도 지정할 수가 있다.
const Input = styled.input.attrs({ required:true })`
background-color: orange;
margin-right: 5px;
`;
required 속성이 성공적으로 적용되었다! 만약에 여러 속성을 주고 싶다면, 다음과 같이 사용하면 된다.
const Input = styled.input.attrs({ required:true, maxLength:10 })`
background-color: orange;
margin-right: 5px;
`;
Styled Components를 통해 애니메이션을 넣기 위해서는 keyframes
를 import 해야 한다.
import {keyframes} from "styled-components";
간단하게 Circle
에 색깔이 바뀌는 애니메이션을 추가해보자.
import {keyframes} from "styled-components";
const CircleAnimation = keyframes`
0% {
background-color:red;
}
33% {
background-color:green;
}
66%
{
background-color:blue;
}
100% {
background-color:red;
}
`;
const Circle = styled(Box)`
border-radius: 50%;
animation: ${CircleAnimation} 3s linear infinite;
`;
const App = () => {
return (
<Wrapper>
<Circle bgColor={"red"} />
</Wrapper>
);
};
주의해야 할 점은, 애니메이션을 컴포넌트보다 먼저 정의해주어야 성공적으로 애니메이션이 적용된다. 순서가 바뀐다면 아래와 같은 에러 메세지를 볼 수 있을 것이다.
'CircleAnimation' was used before it was defined no-use-before-define
마지막으로 가상 선택자에 대해 알아보자!
먼저, 선택자를 알아보기 위해 Box
컴포넌트 내에 span 태그 하나를 추가해보자.
const Box = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
span {
background-color: black;
}
`;
const App = () => {
return (
<Wrapper>
<Box bgColor={"#cf6a87"}>
<span>😊</span>
</Box>
</Wrapper>
);
};
Box
컴포넌트 안에 성공적으로 span이 삽입되었다.
span 위에 마우스를 올렸을 때(hover), 배경 색상을 바꾸기 위해서는 두 가지 방법이 있다.
// 1번 방법
const Box = styled.div`
생략...
span {
background-color: black;
}
span:hover {
background-color: white;
}
`;
// 2번 방법
const Box = styled.div`
span {
background-color: black;
&:hover {
background-color: white;
}
}
`;
두 방법 모두 큰 차이는 없지만, 개인적으로는 2번 방법이 한 눈에 알아보기 편해서 좋다고 생각한다.
프로젝트의 규모가 커질 수록 각각의 파일의 관리가 어려워지기 때문에 하나의 파일 안에서 JS와 CSS를 모두 관리한다는 것은 큰 장점이라고 생각한다.
CSS 파일에서 작성한 class와 id를 올바르게 작성했는지 파일을 이동하지 않아도 되고, Styled Components에서는 같은 컴포넌트 이름을 사용하더라도 다른 파일에 위치하고 있다면 랜덤한 className을 지정하여 주기 때문에 네이밍에 스트레스를 받지 않아도 되기 때문이다.
이 글에서 살펴본 것은 기초적인 문법이지만, 사용하기에 따라 활용도는 무한할 것이라고 생각한다.