본문 바로가기

React

styled Components을 사용한 스타일링

styled Components 패키지는 사용하면 특정 스타일이 첨부된 컴포넌트를 구축할 수 있도록 도와주는 패키지입니다.

 

특정 스타일이 첨부되는 컴포넌트에서만 영향을 미치고 다른 컴포넌트에는 전혀 영향을 미치지 않습니다.

 

 

우선 styled Components 접속하시거나 위의 명령어를 터미널에 입력하여 패키지를 다운로드합니다.

 

styled-components

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

styled-components.com

 

기존 스타일링
import React from 'react';

import './Button.css';

const Button = props => {
  return (
    <button type={props.type} className="button" onClick={props.onClick}>
      {props.children}
    </button>
  );
};

export default Button;

기존에는 Button 컴포넌트를 생성하여 CSS를 import 해 사용해주었습니다.

 

styled Components 패키지를 사용하여 기존의 스타일링을 변경해겠습니다.

 

사용방법
import styled from "styled-components";

우선 styled Components에서 styled를 import 해줍니다.

 

 

const Button = styled.button``;

다음으로 기존 방식처럼 상수 Button을 생성해주지만 해당 상수는 더 이상 함수형 컴포넌트를 저장하지 않기 때문에

 

위의 코드 예시처럼 작성해줍니다.

 

styled는 styled Components에서 import 한 객체이고 button은 styled 객체의 메서드입니다.

 

styled 객체가 호출할 수 있는 메서드는 html에 있는 모든 요소에 대한 메서드입니다.

 

저의 경우 button 컴포넌트를 생성하는 것이 목표이기 때문에 button 메서드를 호출해주었습니다.

 

styled Components 패키지에서는 button()으로 메서드를 호출하는 대신 뒤에 백 틱( `` )을 붙여 호출합니다.

 

이렇게 사용한 button 메서드는 새로운 Button 컴포넌트를 반환하게 됩니다.

 

 

const Button = styled.button`
  .button {
    font: inherit;
    padding: 0.5rem 1.5rem;
    border: 1px solid #8b005d;
    color: white;
    background: #8b005d;
    box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
    cursor: pointer;
  }

  .button:focus {
    outline: none;
  }

  .button:hover,
  .button:active {
    background: #ac0e77;
    border-color: #ac0e77;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
  }
`;

위의 코드처럼 백 틱 사이에는 여러 줄의 문자열을 작성할 수 있습니다.

 

기존의 import 했던 CSS의 코드를 백 틱 사이에 넣어주었습니다.

 

여기서 문제는 button 메서드는 Button 컴포넌트를 반환만 하지 클래스를 따로 지정을 해주지 않기 때문에

 

백 틱 사이의 CSS 코드가 적용이 안된다는 것입니다.

 

대신 백 틱 사이에 전달한 CSS 코드를 button 메서드에 직접적으로 영향을 주게 할 수 있습니다.

 

const Button = styled.button`
  font: inherit;
  padding: 0.5rem 1.5rem;
  border: 1px solid #8b005d;
  color: white;
  background: #8b005d;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
  cursor: pointer;

  &:focus {
    outline: none;
  }

  &:hover,
  &:active {
    background: #ac0e77;
    border-color: #ac0e77;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
  }
`;

위의 코드처럼 선택자를 제거하면 백 틱 사이의 CSS 코드는 메서드가 호출되어 반환하는 Button 컴포넌트에 추가되며

 

상수 Button까지 영향을 받게 됩니다.

 

가상 선택자의 경우는 styled Components 패키지에서 지원하는 & 기호와 사용합니다.

 

& 기호는 생성한 컴포넌트에 대해 가상 선택자를 사용하겠다고 패키지에 선언하는 것을 의미합니다.

 

즉 "버튼에 focus가 있으면 스타일을 적용해줘"를 의미하게 되는 것입니다.

 

만약 .button label처럼 button 클래스 안에 있는 label 태그에 접근을 하고 싶은 경우에도 & 기호를 사용해주시면 됩니다.

( & label )

 

이렇게 생성된 Button 컴포넌트에는 기존에 전달하는 props가 적용되게 됩니다.

 

기존의 button에는 onClick 속성을 추가해서 type을 설정할 수 있는데

 

생성된 Button 컴포넌트는 styled Components에 의해 button 메서드가 내부적으로 사용하고 있습니다.

 

 


기존 코드

 

 return (
    <form onSubmit={formSubmitHandler}>
      <div className={`form-control ${!isValid ? "invalid" : ""}`}>
        {/* isValid가 false이면 글자색 red, true이면 글자색 black */}
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );

 

변경 코드
const FormControl = styled.div`
  margin: 0.5rem 0;

  &.invalid label {
    color: red;
  }

  &.invalid input {
    border-color: red;
    background-color: salmon;
  }

  & label {
    font-weight: bold;
    display: block;
    margin-bottom: 0.5rem;
  }

  & input {
    display: block;
    width: 100%;
    border: 1px solid #ccc;
    font: inherit;
    line-height: 1.5rem;
    padding: 0 0.25rem;
  }

  & input:focus {
    outline: none;
    background: #fad0ec;
    border-color: #8b005d;
  }
`;

return (
    <form onSubmit={formSubmitHandler}>
    // styled-component 적용--------------------------------------------
      <FormControl className={className={!isValid ? "invalid" : ""}}>
    //-----------------------------------------------------------------
        {/* isValid가 false이면 글자색 red, true이면 글자색 black */}
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </FormControl>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};

기존 코드에서 className에 전달했던 form-control은 제거해주어도 적용이 되게 됩니다.

 

기존 코드에서 className에 삼항 연산자로 전달했던

 

${!isValid ? "invalid" : ""} 는 템플릿 리터럴, 즉 백 틱 없이 전달이 가능해집니다.

 

 

동적으로 스타일링하는 또 다른 방법을 아래 코드 예시와 함께 정리해보겠습니다.

  return (
    <form onSubmit={formSubmitHandler}>
      <FormControl invalid={!isValid}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </FormControl>
      <Button type="submit">Add Goal</Button>
    </form>
  );

styled Components 패키지를 사용해 생성한 컴포넌트에 props를 전달해주었습니다.

 

const FormControl = styled.div`
  margin: 0.5rem 0;

  & label {
    font-weight: bold;
    display: block;
    margin-bottom: 0.5rem;
    color: ${(props) => [props.invalid ? "red" : "black"]};
  }

  & input {
    display: block;
    width: 100%;
    border: 1px solid ${(props) => (props.invalid ? "red" : "#ccc")};
    background: ${(props) => (props.invalid ? "red" : "transparent")};
    font: inherit;
    line-height: 1.5rem;
    padding: 0 0.25rem;
  }

  & input:focus {
    outline: none;
    background: #fad0ec;
    border-color: #8b005d;
  }
`;

${} 사이에는 함수를 받을 수 있고 해당 함수는 전달받은 props를 인자로 받습니다.

 

전달받은 props, invalid가 false이면 "red"가 적용되고, true이면 기존의 컬러가 적용되게 동적으로 스타일링을 해주었습니다.

 

이렇게 props에 기반하여 스타일 일부를 동적으로 변경하는 것이 가능합니다.