프론트엔드 기술/React

[React] Styled Components

pogles 2023. 11. 1. 16:29

npm - styled component

styled-components

Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅


React 환경에서 Component 에 스타일을 적용하는데 있어 inline style 을 적용하거나, css 를 import 하여 스타일을 적용하는 방식에는 많은 어려움이 있었다. 이러한 어려움을 최소화하기 위해서 Styled Component 가 등장하였다.


기존 방식의 불편함

inline 방식

const General_App = () => {
  return (
    <div style={{display: "flex"}}>
        <div style={{backgroundColor: "teal", width: 100, height: 100}}></div>
          <span style={{color: "white"}}>Hello, I'm TEXT</span>
        <div style={{backgroundColor: "tomato", width: 100, height: 100}}></div>
    </div>
  )
}
  • inline 방식은 html 태그 안에 작성되므로 html tag 가 길어지게 된다. 이는 유지보수 측면에서 나쁘고 공통된 스타일을 적용하는데 있어서, 같은 코드를 작성해야 되기 때문에 매우 비효율적이므로 지양한다.

css import 방식

.flex-container {
  display: flex;
}

.box-one {
  background-color: teal;
  width: 100px;
  height: 100px;
}

.box-two {
  background-color: tomato;
  width: 100px;
  height: 100px;
}

.text {
  color: white;
}
import "./style.css"
const General_App = () => {
  return (
    <div className="flex-container">
        <div className="box-one"></div>
          <span className="text">Hello, I'm TEXT</span>
        <div className="box-two"></div>
    </div>
  )
}
  • css 를 import 하는 방식은 유지보수를 위하여 2개의 파일을 관리해야한다. 또한 자동트래킹을 할 수가 없어 특정 Component 를 수정하기 위해서는 className 및 id 를 확인하여 직접 css 파일에서 찾아 수정해야되기 때문에 불편하다.

  • css 를 import 하는 방식은 해당 파일에 작성된 Component 뿐만 아니라 전체 Component 들에 스타일이 적용되기 때문에, 여전히 식별자의 이름을 중복되지 않게 고려해야하는 불편함이 있다.



Styled Component 의 적용

위에서 발생한 여러움들을 최소화 하기 위하여 Styled Component 가 나타났다.

const FlexContainer = styled.div`
  display: flex;
`;

const BoxOne = styled.div`
  background-color: teal;
  width: 100px;
  height: 100px;
`;

const BoxTwo = styled.div`
  background-color: tomato;
  width: 100px;
  height: 100px;
`;

const Text = styled.span`
  color: white;
`;

const Styled_App = () => {
  return (
    <FlexContainer>
        <BoxOne>
          <Text>Hello, I'm TEXT</Text>
        </BoxOne>
        <BoxTwo />
    </FlexContainer>
  )
}
  • 하나의 Component 에 대한 코드와 스타일 정보가 한 파일에 있어서 유지보수하기 손쉬워졌다
  • html 와 css 요소에대해서 분리되어 있어 각 기능에 집중할 수 있다.


1. 기본사용법

/*
  styled.html태그 `
    css 코드;
  `
*/
const Container = styled.div`
  background-color: white;
`

const Styled_App = () => {
  return (
   <Container>
   </Container>
  )
}
  • styled commponent 또한 Component 이기 때문에 이름 또한 대문자로 시작해야한다.


2. 외부로부터 속성받기

styled commponent 가 외부로부터 값을 전달받아, 값에 따라 스타일을 변경할 수 있도록 만들 수 있다.

예를 들어 첫번째 Box Component 는 배경색이 검은색이고, 두번째 Box Component 는 배경색을 갖도록 스타일을 설정할 수 있다.

이렇게 작성하면 Box Component 들은 배경색 이외에는 같은 스타일을 갖는다.


<Component 속성명="속성값" />
css 속성: ${(props) => props."속성명"}

2-1. 배경색만 다른 같은 Component

// 설정변경 가능한 컴포넌트 생성
const Box = styled.div`
  background-color: ${(props) => props.bgColor};
  width: 100px;
  height: 100px;
`;

const App = () => {
  return(
    <div>
      <Box bgColor="black"></Box>
      <Box bgColor="green"></Box>
    </div>
  )
}
  • Styled Component 안에 속성을 지정하면 Styled Component 의 props 에 저장된다.
  • 전달된 속성은 props."속성명" 에 저장된다.
  • Styled Component 안의 스타일 코드에서 ${(props) => props."속성명"}으로 값을 반환받을 수 있다.

2-2. 스위칭되는 배경 스타일

const Container = styled.div`
  background-color: ${(props) => props.darkmode ? "black" : "white"};
`

const Switch = styled.button`
  width: 50px;
  height: 50px;
  color: ${(props) => props.darkmode ? "white" : "black"};
`

const App = () => {
  const [darkmode, setDarkmode] = useState(false);
  const switching = (prev) => setDarkmode(!prev);
  return(
    <Container darkmode={darkmode}>
      <Switch darkmode={darkmode} onClick={switching}>스위칭 버튼</Switch> 
    </Container>
  )
}
  • useState 를 통해서 같은 Component 의 스타일도 동적으로 변경할 수 있다.


2. Styled Component 확장(상속)

Styled Component 는 기존 존재하던 스타일을 받아 확장할 수 있다.

styled(확장할 Component)

const Parent = styled.div`
  display: flex;
`

const ChildOne = styled(Parent)`
  flex-direction: row;
`

const ChildTwo = styled(Parent)`
  flex-direction: column;
`

const App = () => {
  return(
    <Parent>

      <ChildOne>
        <span>1<span>
        <span>2<span>
        <span>3<span>
        <span>4<span>
      </ChildOne>

      <ChildTwo>
        <span>1<span>
        <span>2<span>
        <span>3<span>
        <span>4<span>
      </ChildTwo>

    </Parent>
  )
}
  • ChildOne, ChildTwo 는 Parent 의 스타일을 확장시켰다. 스타일을 상속받는 것처럼 Parent 의 스타일에 영향을 받는다.


3. 적용되는 html tag 변경

서로 다른 HTML tag 이지만, 같은 스타일을 적용시키고 싶을 때 사용할 수 있는 방법이다.


<Component as="a" />     a tag 로 변경
<Component as="p" />     p tag 로 변경
<Component as="div" />   div tag 로 변경

const Text = styled.span`
  max-width: 200px;
  min-height: 40px;
`

const App = () => {
  return(
    <div>
      <Text as="a"> a tag 로 변경 </Text>
      <Text as="p"> p tag 로 변경 </Text>
      <Text as="div"> div tag 로 변경 </Text>
    </div>
  )
}


3. Component 의 속성 지정

input 이나 button 의 경우 속성을 지정해야할 때가 있다. 이러한 경우에도 Styled Component 가 기능을 제공한다.


styled."html-tag".attrs({속성명1: 속성값, 속성명2: 속성값2})``

Styled Component 로 input 의 disable, required 속성 지정하기

const Input = styled.input.attrs({disable: true, required: true})`
  width: 100px;
  heightL 40px;
`

const App = () => {
  return (
    <div>
      <Input />
    </div>
  )
}


4. Animation 지정

Styled Component 에서 keyframes 를 통해서 Component 의 애니메이션 속성을 추가할 수 있다


const userAnimation = keyframes`
  애니메이션 속성
`
const Component = styled.div`
  animation: ${userAnimation};
`

무한회전하는 사각형 애니메이션

import styled, { keyframes } from "styled-components";

const rotationAnimation = keyframes`
  0% {
    border-radius: 0px;
    transform: rotate(0deg);
  }
  50% {
    border-radius: 100px;
    transform: rotate(360deg);
  }
  100%{
    border-radius: 0px;
    transform: rotate(0deg);
  }
`

const Squre = styled.div`
  width: 200px;
  height: 200px;
  background-color: tomato;

  display: flex;
  justify-content: center;
  align-items: center;
  animation: ${rotationAnimation} 1s linear infinite;
`

const Animation = () => {
  <div>
    <Squre />
  </div>
}


5. 이외의 편리기능

5.1 특정 Component 내의 자식 Component

특정 Component 내의 자식 Component 에 대해서도 각각 다른 스타일을 지정할 수 있다.


기존 예시 : flex-container 클래스 안의 span 에 대한 스타일 설정

.flex-container {
  display: flex;
  justify-contents: center;
  align-items: center;
}

.flex-container h2 {
  color: blue;
  text-decoration: underline;
}

.flex-container .child {
  color: red;
  text-align: left;
}

```js
const App = () => {
  return(
    <div className="flex-container">
      <h2>flex container 클래스 내 h2 에서만 적용</h2>
      <span className="child">flex container 클래스 내 child 클래스에서만 적용t</span>
    </div>
  )
}

Styled Component : flex-container 클래스 안의 span 에 대한 스타일 설정

  • 특정 Component 에 속하는 자식 Component 에 대해서, 한번에 표현할 수 있어 작성하기가 편하다는 장점이 있다.

const Child = styled.span`
  color: red;
  text-align: left;
`
const FlexContainer = styled.div`
  display: flex;
  justify-contents: center;
  align-items: center;

  // FlexContainer 내의 p tag 에만 적용
  p {
    color: red;
    text-align: left;
  }

  // FlexContainer 내의 Child Component 에만 적용
  ${Child} {
    color: red;
    text-align: left;
  }
`

const App = () => {
  return(
    <FlexContainer>
      <h2>flex container 클래스 내 h2 에서만 적용</h2>
      <Child>flex container 클래스 내 child 클래스에서만 적용</Child>
    </FlexContainer>
  )
}



5.2 pseudo-class 설정


& 키워드 사용
const Component = styled.div`
  &:hover {
  }
  &:active {
  }
  ...
`

위와 마찬가지로 다양한 pseudo class 에 대한 설정을 한 코드박스 안에 모두 설정할 수 있다.

한 Component 에 대한 스타일 설정을 한 코드박스안에 넣을 수 있어, 코드가 간결해진다.

기존코드 : flex-container 클래스에 대하여 hover, active 설정

  • hover 시 scale: 0.8
  • active 시 background-color: gray
.flex-container {
  width: 100px;
  height: 100px;
  display: flex;
}

.flex-container:hover {
  scale: 0.8;
}

.flex-container:active {
  background-color: gray;
}

Style Component : FlexContainer 에 대하여 hover, active 설정

const FlexContainer = styled.div`
  width: 100px;
  height: 100px;
  display: flex;
  &:hover {
    scale: 0.8;
  }
  &:active {
    background-color: gray;
  }
`