본문 바로가기
JS/React 강의

[React] 12. CSS 모듈 사용하기

by GiraffePark 2023. 3. 28.

안녕하세요. 박기린 입니다.

이번엔 ReactJS의 스타일링 모듈인 CSS에 대해 알아보겠습니다.

 

css 모듈을 사용하는 이유

모든 React 프로젝트에는 css모듈이 내장되어 있습니다.

기존의 css 파일은 컴포넌트 단위가 아니라 전역 단위로 적용이 되는 탓에 문제가 발생하였고, 이를 해결하기 위해 styled-components라는 외부 모듈을 사용한다고 저번에 소개를 해드렸습니다.

 

외부 모듈을 설치하는 방법 대신에, React에 내장된 css 모듈을 이용해서 컴포넌트 단위로 스타일링을 할 수 있습니다.

 

 

 

 


css 모듈 사용해보기

import React from "react";
import styles from "./Button.module.css";
const Button = props => {
  return (
    <button type={props.type} className={styles.button} onClick={props.onClick}>
      {props.children}
    </button>
  );
};

export default Button;

위 Button 컴포넌트는 css 모듈이 사용된 컴포넌트 입니다.

 

 

 

import styles from "./Button.module.css";

- css 파일을 생성할 때, fileName.module.css 형식으로 이름을 지정합니다. 그러면 css 모듈이 컴파일 프로세스에서 '컴포넌트 단위로 css가 적용되게 끔 고유 class 코드를 지정하라'고 신호를 보냅니다.

- 이 module.css 파일을 import 할 때, 관례로 styles 또는 classes로 이름을 붙입니다. 이 글에서는 styles라고 가정을 하고 설명을 드리겠습니다.

- styles는 Object입니다. css 파일의 모든 class들은 styles object의 property가 됩니다. React 컴포넌트들은 className props를 가지는데, 이 안에 styles.property를 전달해주면 됩니다.

 

 

 

Button.js가 build된 후, index.html에서 확인한 모습입니다. 위의 Button.js 컴포넌트가 module.css와 결합하여 고유한 class가 부여된 모습입니다. 이렇게 css 모듈을 통해서, css 파일만을 가지고도 컴포넌트 단위의 스타일링이 가능합니다.

 

 

 

 

 

 


css 모듈을 사용한 동적 스타일링

css 모듈 역시 동적 스타일링이 가능합니다.

 

      <div className={`${styles['form-control']} ${!isValid && styles.invalid}`}>

css 모듈의 원리는

1. styles 객체에서 'form-control'이라는 string을 추출하고,
2. module.css 파일에서 같은 string을 지닌 class와 매칭한 후,
3. 유니크한 값을 가진 클래스로 변환하여 컴포넌트에 전달합니다.

그렇기에 결국 styles object의 property는 string 타입이라는 의미이고, 따라서 템플릿 리터럴을 적용할 수 있습니다. 템플릿 리터럴을 이용해서 동적인 스타일링을 구현합니다.

 

 

 

+) JavaScript는 property 이름에 '-' 기호가 들어가면 뺄셈 연산자로 인식해서 오류가 발생합니다. 이를 해결하기 위한 방법으로 [대괄호]와 '작은 따옴표'를 사용하면 됩니다. 

styles[form-control]

objctName['property-Name']으로 지정하면 '-'가 적혀 있어도 정상적으로 property에 접근할 수 있다. '-'까지 string으로 인식해주기 때문이다.

 

 

 

 

 

 


포함된 class의 경우

.form-control.invalid input {
  border-color: red;
  background: #ffd7d7;
}

.form-control.invalid label {
  color: red;
}

위처럼 form-control class에 invalid class가 포함된 경우, 역시 styles 객체에서 추출한 string을 넘겨주지 않으면 컴포넌트 단위의 고유한 스타일링을 할 수 없습니다.

 

 

${styles['form-control']} ${!isValid && styles.invalid}

그래서 'invalid'만 className에 넘기는 게 아니라, 'styles.invalid'로 넘겨줘야 합니다.

 

 

 

 

 

 


커스텀 컴포넌트에 className을 전달할 경우

    <Card className={styles.input}>
      <form onSubmit={addUserHandler}>
        {/* html의 for attribute를 jsx에서는 htmlFor이라고 부른다. for은 js의 예약어라서 그렇다. */}
        <label htmlFor="username">Username</label>
        <input id="username" type="text" />
        <label htmlFor="age">Age (years)</label>
        <input id="age" type="number" />
        <button type="submit">Add User</button>
      </form>
    </Card>

위 jsx 코드는 <Card>라고 하는 (직접 만든) 커스텀 컴포넌트를 사용합니다. 그리고 Card.module.css 파일이 존재하여 따로 Card.js 자체에서 css 모듈을 사용하고 스타일링한 상황입니다.

 

 

하지만 만약 상위 컴포넌트에서 <Card> 컴포넌트를 사용할 때, 상위 컴포넌트에 연결된 module.css 스타일링을 동시에 적용시키길 원한다면 어떻게 해야 할까요?

import React from 'react';
import styles from './Card.module.css';

const Card = (props) => {
  const classes = `${styles.card} ${props.className}`;
  return <div className={classes}>{props.children}</div>;
}

그러면 커스텀 컴포넌트 파일(Card.js)에서 classes라는 string 상수/변수를 만든 후, `템플릿 리터럴`을 이용해서,

 

const classes = `${styles.card} ${props.className}`;

styles.기존className + props.className을 넣어주면, 커스텀 컴포넌트에서도 css 모듈이 동시에 잘 작동됩니다.

반응형