Front-End

vsoghlv@naver.com

React.js css module

React 프로젝트에서 컴포넌트를 스타일링 할 때 CSS Module 을 사용하면 CSS 클래스가 중첩되는 것을 방지할 수 있다. 사용법은 간단한데 CSS 파일 확장자를 .module.css 로 하면 된다.

Box.module.css 라는 파일을 만든 후 .Box 에 대한 스타일을 만들어보자

/*Box.module.css*/
.Box {
  background: black;
  color: white;
  padding: 2rem;
}

CSS 파일내에서 사용방법은 같지만 컴포넌트 파일에서 불러올 때 조금 다르게 불러온다. 아래와 같이 import styles from "./Box.module.css"; styles 를 붙여 불러온 후 className 을 설정할 때 styles.Box 와 같이 import 로 불러온 styles 를 참조하면 된다. 이렇게 하면 className 에 파일경로, 이름, 해쉬값, 클래스이름등이 사용 되어 만들어진다.

import React from "react";
import styles from "./Box.module.css";

function Box() {
  return <div className={styles.Box}>{styles.Box}</div>;
}

export default Box;
<div class="_src_Box_module_Box">_src_Box_module_Box</div>    

조금 더 자세히 알아보기 위해 새로운 프로젝트를 작성하고 체크값에 따라 변화되는 인풋을 만들어보자

//App.js
import React, { useState } from "react";
import CheckBox from "./components/CheckBox";

function App() {
  const [check, setCheck] = useState(false);
  const onChange = (e) => {
    setCheck(e.target.checked);
  };
  return (
    <div className="App">
      <CheckBox onChange={onChange} checked={check}>
        다음 약관에 모두 동의
      </CheckBox>
    </div>
  );
}

export default App;

//CheckBox.js
import React from "react";

function CheckBox({ checked, children, ...rest }) {
  return (
    <div>
      <label>
        <input type="checkbox" {...rest} checked={checked} />
        <div>{checked ? "체크" : "체크안됨"}</div>
      </label>
      <span>{children}</span>
    </div>
  );
}

export default CheckBox;

checked 와 children 을 제외한 나머지 props 를 간단히 받아오기 위해 …rest 를 사용했다.

이제 인풋을 가리고 체크에 대한 내용을 아이콘으로 변경해줄건데 이를 위해 ract-icons 라는 라이브러리를 사용하려고 한다.

yarn add react-icons

로 설치한 후 사용하면 되는데 자세한 사용법과 아이콘의 모양은 https://react-icons.github.io/react-icons/#/ 에서 확인이 가능하다.

import { MdCheckBox, MdCheckBoxOutlineBlank } from "react-icons/md";

function CheckBox({ checked, children, ...rest }) {
  return (
    <div>
      <label>
        <input type="checkbox" {...rest} checked={checked} />
        <div>{checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}</div>
      </label>
      <span>{children}</span>
    </div>
  );
}

이제 CSS.mocule 파일을 만들어 주는데 여기서는 클래스 이름이 중복될 걱정을 하지 않아도 된다. 아래와 같이 작성한 후

/*CheckBox.module.css*/
.checkBox {
  display: flex;
  align-items: center;
}

.checkBox label {
  cursor: pointer;
}

.checkBox input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
}

.checkBox span {
  font-size: 1.125rem;
  font-weight: bold;
}

.icon {
  display: flex;
  align-items: center;
  font-size: 2rem;
  margin-right: 0.25rem;
  color: #2e2e2e;
}

.checked {
  color: #1376be;
}

CheckBox.js 에서 콘솔을 찍어 확인해 보면 아래와 같이 고유한 클래스 네임이 생성된 것을 볼 수 있다.

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

console.log(styles);
//checkBox: "CheckBox_checkBox__1uvSa"
//checked: "CheckBox_checked__2D8y_"
//icon: "CheckBox_icon__2zG6x"
function CheckBox({ checked, children, ...rest }) {
  return (
    <div className={styles.checkBox}>
      <label>
        <input type="checkbox" {...rest} checked={checked} />
        <div className={styles.icon}>
          {checked ? (
            <MdCheckBox className={styles.checked} />
          ) : (
            <MdCheckBoxOutlineBlank />
          )}
        </div>
      </label>
      <span>{children}</span>
    </div>
  );
}

위와 같이 styles 를 불러온 후 styles 객체안의 값을 조회하는 형태로 사용하면 된다.

만약 하나에 두가지 이상의 클래스 네임이 들어갈 경우 작성하기가 번거로워 지는데 이때는 classnames 라이브러리르 통해 조금 더 편하게 사용할 수 있다.

yarn add classnames

설치 후 불러올 때 /bind 를 불러오는데 바인드는 CSS 모듈을 사용할 때 조금 더 쉽게 사용할 수 있도록 도와주는 유틸이다.

import classNames from "classnames/bind";

const cx = classNames.bind(styles);

먼저 변수에 classNames.bind 를 통해 styles 를 담아준 후

function CheckBox({ checked, children, ...rest }) {
  return (
    <div className={cx("checkBox")}>
    {/* <div className={cx("checkBox"), "다른 클래스", props}> */}
      <label>
        <input type="checkbox" {...rest} checked={checked} />
        <div className={cx("checkbox")}>
          {checked ? (
            <MdCheckBox className={cx("checkbox")} />
          ) : (
            <MdCheckBoxOutlineBlank />
          )}
        </div>
      </label>
      <span>{children}</span>
    </div>
  );
}

위와 같은 방식으로 사용해 주면된다.

혹시 module.css 내부에서 글로벌로 사용하고 싶은 이름이 있다면 글로벌 키워드를 넣어주면 된다.

/* ex.module.css*/

:global .mt-global-name{

}

/* ex.module.scss*/

:global {
  .mt-global-name{

  }
}

반대로 모듈을 사용하지 않은 CSS 파일에서 local 키워드를 넣어주면 CSS module 형태로 사용할 수 있다.

/* ex.module.css*/

:local .mt-global-name{

}

/* ex.module.scss*/

:local {
  .mt-global-name{

  }
}