React 2021년 마지막 일요일 #19

CoderS·2021년 12월 26일
0

리액트 Remind

목록 보기
19/32

#19 크리스마스 종료!

CSS Module

이번에는 CSS Module 이라는 기술에 대해 알아보자!

우리가 리액트 프로젝트에서 컴포넌트를 스타일링 할 때, CSS Module 이라는 기술을 사용하면, CSS 클래스가 중첩되는 것을 막을 수 있다.

프로젝트에서 CSS Module 을 사용할 때, CSS 확장자 파일을 .module.css 로 하면되고 예를 들어서 Box.module.css 라는 파일을 만든다면...

Box.module.css

.Box {
  background: black;
  color: white;
  padding: 2rem;
}

리액트 컴포넌트 파일에서 CSS 파일을 불러올 때 CSS 파일에 선언한 클래스 이름들이 모두 고유해진다. 고유 CSS 클래스 이름이 만들어지는 과정에서는 파일 경로, 파일 이름, 클래스 이름, 해쉬값 등이 사용이 될 수 있다.

Box 컴포넌트를 다음과 같이 코드를 작상하면...

Box.js

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

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

export default Box;

className 을 설정 할 때에는 styles.Box 이렇게 불러온 styles 객체 안에 있는 값을 참조한다.

클래스 이름에 관해서 고유한 이름들이 만들어지기 때문에, 다른 관계 없는 곳에서 CSS 클래스 이름이 중복되는 일은 없다.

리액트 컴포넌트를 위해 클래스를 작성할 때 자주 사용하는 CSS 클래스 네이밍 규칙이 다름과 같이 존재한다.

  1. 컴포넌트의 이름은 다른 컴포넌트와 중복되지 않게 한다.
  2. 컴포넌트의 최상단 CSS 클래스는 컴포넌트 이름과 일치시킨다.
  3. 컴포넌트 내부에서 보여지는 CSS 클래스는 CSS Selector 를 잘 활용한다.

만약 CSS 클래스 네이밍 규칙을 만들고 따르기 싫다면, CSS Module 을 사용하면 된다.

이번 튜토리얼에서도 새로운 리액트 프로젝트를 생성해서 CSS Module 기술을 접목한 컴스텀 체크박스 컴포넌트를 만들어 사용해보겠다.

우선 새로운 프로젝트를 생성해준다.

$ npx create-react-app styling-with-css-module

그리고 CSS Module 은 별도로 설치해야 할 라이브러리는 없으니 바로 사용하면 된다.

우선 src 디렉토리에 components 디렉토리를 만들고 그 안에 CheckBox.js 를 생성해준다. 먼저 CheckBox 컴포넌트 틀을 준비해준다.

components/CheckBox.js

import React from 'react';

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

export default CheckBox;

지금은 스타일링을 하지 않고, 그냥 컴포넌트에 필요한 HTML 태그들만 선언 해주었다.

위에 코드를 보면, ...rest 를 사용한 이유는, CheckBox 컴포넌트에게 전달하게 될 name, onChange 같은 값을 그대로 input 에게 넣어주기 위함이다.

이제 App 컴포넌트에서 렌더링해준다.

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>
      <CheckBox onChange={onChange} checked={check}>
        다음 약관에 모두 동의
      </CheckBox>
      <p>
        <b>check: </b>
        {check ? 'true' : 'false'}
      </p>
    </div>
  );
}

export default App;

이제 서버를 실행해서 확인해보면...

체크하기 전에...

체크를하고 난 후...

우리는 확인할 수 있는것은 input 이 아닌 텍스트 부분을 클릭했는데도, 값이 바뀌는 이유는 우리가 해당 내용을 label 태그로 감싸줬기 때문이다.

이제 스타일링을 하기 앞서, react-icons 라는 라이브러리를 설치해준다.

$ npm install react-icons

이 라이브러리를 사용하면 Ionicons, Font Awesome, Material Design Icons, 등의 아이콘들을 컴포넌트 형태로 쉽게 사용 할 수 있다.

우리는 그 중에 Material Design Icons 의 MdCheckBox, MdCheckBoxOutline 을 사용하겠다.

출처 : 벨로퍼트와 함께하는 모던 리액트

CheckBox 컴포넌트를 다음과 같이 수정해준다.

components/CheckBox.js

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

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

export default CheckBox;

체크박스 체크하기 전...

체크박스 체크한 후...

아이콘들을 불러오면 텍스트 대신 아이콘이 나타나게 된다.이제 컴포넌트를 스타일링 해보겠다.

CheckBox.module.css 파일을 components 디렉토리에 생성한 후 다음과 같이 코드를 작성해준다.

components/CheckBox.module.css

.checkbox {
  display: flex;
  align-items: center;
}

.checkbox label {
  cursor: pointer;
}

/* 실제 input 을 숨기기 위한 코드 */
.checkbox input {
  width: 0;
  height: 0;
  position: absolute;
  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: #adb5bd;
}

.checked {
  color: #339af0;
}

우리가 CSS Module 을 작성할 때에 CSS 클래스 이름이 다른 곳에서 사용되는 CSS 클래스 이름과 중복될 일이 없기 때문에 .icon, .checkbox 같은 짧고 흔한 이름을 사용해도 상관이 없다.

CSS 코드를 다 작성했으면 CheckBox 파일에 적용해준다.

components/CheckBox.js

import React from 'react';
import { MdCheckBox, MdCheckBoxOutlineBlank } from 'react-icons/md';
import styles from './CheckBox.module.css';

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

export default CheckBox;

잘 반영이 되었는지 확인해준다.

체크하기 전...

체크한 후...

만약에 클래스 이름에 - 이 들어갈 때, 다음과 같이 작성해줘야 한다.

styles['my-class']

그리고 여러개가 있다면 다음과 같이 작성해준다.

${styles.one} ${styles.two}

조건부 스타일링을 하면은 더욱 복잡해진다.

${styles.one} ${condition ? styles.two : ''}

이전에 Sass 를 배울 때, classnames 라이브러리에는 bind 라는 기능이 있는데, 이 기능을 사용하면 CSS Module 을 조금 더 편하게 사용 할 수 있다.

그럼, 바로 설치해준다.

$ npm install classnames

그리고 CheckBox.js 를 다음과 같이 수정해준다.

components/CheckBox.js

import React from 'react';
import { MdCheckBox, MdCheckBoxOutlineBlank } from 'react-icons/md';
import styles from './CheckBox.module.css';
import classNames from 'classnames/bind';

const cx = classNames.bind(styles);

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

export default CheckBox;

classnames 의 bind 기능을 사용하면, CSS 클래스 이름을 지정해 줄 때 cx('클래스이름') 과 같이 편한 형식으로 사용 할 수 있다.

특히 여러개의 CSS 클래스나 조건부 스타일링을 해야 한다면 더욱 편리해진다.

cx('one', 'two')
cx('my-component', {
  condition: true
})
cx('my-component', ['another', 'classnames'])

참고로, CSS Module 은 Sass 에서도 사용이 가능하다. 확장자를 .module.scss 로 바꿔주면 된다. 물론, node-sass 를 설치해줘야 한다.

그리고, CSS Module 을 사용하고 있는 파일에서 클래스 이름을 고유화 하지 않고 전역적 클래스이름을 사용하고 싶다면 다음과 작성하면 된다.

:global .my-global-name {

}

Sass 를 사용하면 다음과 같이 된다.

:global {
  .my-global-name {

  }
}

하지만, CSS Module 을 사용하지 않는 곳에서 특정 클래스에서만 고유 이름을 만들어서 사용하고 싶다면 다음과 같이 할 수 있다.

:local .make-this-local {

}

Sass 를 사용하면 다음과 같이 표현할 수 있다.

:local {
  .make-this-local {

  }
}

참고 : 벨로퍼트와 함께하는 모던 리액트

느낀점 :

  • 오늘은 CSS Module을 사용하는 방법을 배워봤다.
  • 이 기능은 CSS 클래스를 중복되지 않게 작성하기 위하여 CSS 클래스 네이밍 규칙을 만들기 귀찮을 때 사용하면 좋다.
profile
하루를 의미있게 살자!

0개의 댓글