본문 바로가기

클라이언트/React
[리액트(React)] styled-components

// styled-components

- css 문법을 사용하며, 결과물을 컴포넌트 형태로 만들어주는 오픈 소스 라이브러리

- 설치

npm i --save styled-components

yarn add styled-components

const 컴포넌트명 = styled.HTML요소명`
    color: #6b7280;
`;

<컴포넌트명></컴포넌트명>

- tagged template literal을 사용하여 구성 요소의 스타일을 지정한다.
   ~ tagged template literal : 템플릿 리터럴 앞에 함수를 두는 형태 > 파라미터로 템플릿 리터럴 사용

const 컴포넌트명 = styled.HTML요소명`    
    color: ${(props) => props.props명? 값1: 값2};
`;

const 컴포넌트명 = styled.HTML요소명`    
    color: ${({props명}) => props명? 값1: 값2}; 
`;


<컴포넌트명 props명={조건}></컴포넌트명>

- 동적으로, 조건적으로 스타일링 하기 위해서는 props를 받아 함수로 처리할 수 있다.

const 컴포넌트명 = styled.HTML요소명`    
    color: ${($props) => $props.props명? 값1: 값2};
`;

const 컴포넌트명 = styled.HTML요소명`    
    color: ${({$props명}) => $props명? 값1: 값2}; 
`;

<컴포넌트명 $props명={조건}></컴포넌트명>

※ 동적으로 속성을 삽입할 때, 기본 내장 속성과 충돌하지 않도록 주의해야 한다.
styled components 스타일링 코드에서만 사용하고 싶은 속성에는 일반적으로 $ 기호를 사용한다.


import { useState } from 'react';
import { styled } from 'styled-components';

const ControlContainer = styled.div`
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
`;

const Label = styled.label`
  display: block;
  margin-bottom: 0.5rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: ${({ $invalid }) => ($invalid ? '#f87171' : '#6b7280')};
`;

const Input = styled.input`
  width: 100%;
  padding: 0.75rem 1rem;
  line-height: 1.5;
  background-color: ${({ $invalid }) => ($invalid ? '#fed2d2' : '#d1d5db')};
  color: ${({ $invalid }) => ($invalid ? '#ef4444' : '#374151')};
  border: 1px solid ${({ $invalid }) => ($invalid ? '#f73f3f' : 'transparent')};
  border-radius: 0.25rem;
  box-shadow:
    0 1px 3px 0 rgba(0, 0, 0, 0.1),
    0 1px 2px 0 rgba(0, 0, 0, 0.06);
`;

export default function AuthInputs() {
  return (
    <div id="auth-inputs">
      <ControlContainer>
        <p>
          <Label $invalid={emailNotValid}>Email</Label>
          <Input
            type="email"
            $invalid={emailNotValid}
            onChange={(event) => handleInputChange('email', event.target.value)}
          />
        </p>
        <p>
          <Label $invalid={passwordNotValid}>Password</Label>
          <Input
            type="password"
            $invalid={passwordNotValid}
            onChange={(event) =>
              handleInputChange('password', event.target.value)
            }
          />
        </p>
      </ControlContainer>
    </div>
  );
}

// 자식 요소 선택

- styled.HTML요소로 사용할 때, 해당 요소의 하위에 있는 요소들까지 styling 하고자 할 때, & 기호를 사용한다.
  (필수는 x)

const 컴포넌트명 = styled.HTML요소명`
    color: #6b7280;
    
    & 하위HTML요소명 {
        color: #ffffff;
    }
`;

<컴포넌트명>
    <하위HTML태그>
    </하위HTML태그>
</컴포넌트명>


- pseudo 선택자를 사용할 때는 &뒤에 빈 공간을 남기지 않고 이어서 사용한다.

const 컴포넌트명 = styled.HTML요소명`
    color: #6b7280;
    
    & 하위HTML요소명:pesudo선택자 {
        color: #ffffff;
    }
`;

<컴포넌트명>
    <하위HTML태그>
    </하위HTML태그>
</컴포넌트명>

import logo from '../assets/logo.png';
import { styled } from 'styled-components';

const StyleHeader = styled.header`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-top: 2rem;
  margin-bottom: 2rem; 
  
  &:hover {
    background-color: white;
  }

  & img {
    object-fit: contain;
    margin-bottom: 2rem;
    width: 11rem;
    height: 11rem;
  }

  & h1 {
    font-size: 1.5rem;
    font-weight: 600;
    letter-spacing: 0.4em;
    text-align: center;
    text-transform: uppercase;
    color: #9a3412;
    font-family: 'Pacifico', cursive;
    margin: 0;
  }


  & p {
    text-align: center;
    color: #a39191;
    margin: 0;
  }

  @media (min-width: 768px) {
    margin-bottom: 4rem;

    & h1 {
      font-size: 2.25rem;
    }
  }
`;

export default function Header() {
  return (
    <StyleHeader>
      <img src={logo} alt="A canvas" />
      <h1>ReactArt</h1>
      <p>A community of artists and art-lovers.</p>
    </StyleHeader>
  );
}

// extends

- 기존 styled-components를 확장하여 재사용할 수 있다.

const 컴포넌트명1 = styled.HTML요소`
  //내용
`;

const 컴포넌트명2 = styled(컴포넌트명1)`
  //추가
`;

const Box = styled.div`
  background-color: ${({ bgColor }) => bgColor};
  width: 100px;
  height: 100px;
`;

const Circle = styled(Box)`
  border-radius: 50%;
`;

// as

- 확장해서 추가하지 않고, 같은 컴포넌트인데 HTML 요소만 바꾸고 싶을 때 사용한다.

<컴포넌트명 as="바꾸고싶은HTML요소명">

function App() {
  return (
    <Father>
      <Btn as="a" href="/">
        Log in
      </Btn>
    </Father>
  );
}

// attiribute

- styled component 자체에 속성을 추가할 수 있다.

const 컴포넌트명 = styled.HTML요소.attrs({ 추가할attribute: 값 })`
  //내용
`;

const Input = styled.input.attrs({ required: true })`
  background-color: tomato;
`;

// animation

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

- keyframes를 추가로 import 해준다.

const 애니메이션명 = keyframes`
  from{  }
  to {  }
`;

- 애니메이션을 정의한다.

const 컴포넌트명 = styled.HTML요소`
  animation: ${애니메이션 요소} 기타설정;
`;

- 사용하고자 하는 styled-component의 animation에 ${} 로 추가해준다.


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

const Box = styled.div`
  height: 200px;
  width: 200px;
  background-color: tomato;
  display: flex;
  justify-content: center;
  align-items: center;
  animation: ${rotationAnimation} 1s linear infinite;
  span {
    font-size: xxx-large;
  }
`;

// theme

- 전체적인 테마를 결정한다.


1. 설정

const 테마명 = {
  //내용
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <ThemeProvider theme={테마명}>
      <App />
    </ThemeProvider>
  </React.StrictMode>,
);

- ThemeProvider로 App 컴포넌트를 감사고, theme property에 원하는 테마변수를 넘겨준다.


const styled-component명 = styled.HTML요소`
  property명: ${(props) => props.theme.테마변수의property명};
`;

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { ThemeProvider } from 'styled-components';

const lightTheme = {
  textColor: '#111',
  backgroundColor: 'whitesmoke',
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <ThemeProvider theme={lightTheme}>
      <App />
    </ThemeProvider>
  </React.StrictMode>,
);

 

const Wrapper = styled.div`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: ${(props) => props.theme.backgroundColor};
`;

const Title = styled.h1`
  color: ${(props) => props.theme.textColor};
`;