CSS modules 사용 후기

Yeongjong Kim·2022년 1월 27일
0

CSS mosules는 css를 모듈처럼 사용할 수 있는 장점이 있다.
원리는 보면 클래스 명을 해쉬 값을 붙여 다시 생성하고, 그 값을 모듈로 내보내서 사용하는 것이다.

style.css

.table {
  width: 1rem;
}

component.js

import styles from 'component/style.css'

export default function test () {
  return <div className={styles.table}
}

styles에는 객체 형식으로 { table: table-hash } 클래스 이름이 Key가 되고 재 생성한 클래스 이름이 Value가 되어 객체의 프로퍼티로 접근하여 사용하는 구조다.

기존 css에서 클래스가 중복될 수 있다는 문제를 타파하기 위해 BEM과 같은 네이밍 규칙을 사용했었는데, 이를 해결한 아주 좋은 도구다.

그런데 불편한 점이 한 가지 있다. 모든 class, id 등이 해쉬를 붙여 재생성 되기 때문에, 자식을 선택하기 힘들어진다.

자식을 선택하기 힘들다고 ❓

예를 들어, grid로 만들어진 테이블 row에 border를 적용하려고 한다. 어떤 방법을 사용할 수 있을까?
row 마다 모두 border를 4방으로 적용하면 중첩되는 보더가 생겨서 UI 깨져버린다. 그래서 자식을 선택해서 border를 적용하면 비교적 간하게 중첩되지 않고 보더를 적용할 수 있다.

style.css

.table {
  border: solid 1px black;
}

.table .tableRow:not(:last-child) {
  border-bottom: solid 1px black;
}

component.js

import styles from 'component/style.css'

export default function test () {
  return <Table className={styles.table}>
    <TableRow className="tableRow"/>
    <TableRow className="tableRow"/>
  </Table>
}

문제의 시작

위의 코드는 동작하지 않는다. 왜냐? css modules는 .table .tableRow에서 선택된 .tableRow class를 모듈화시킨다.

style.css

.table-hash {
  border: solid 1px black;
}

.table-hash .tableRow-hash:not(:last-child) {
  border-bottom: solid 1px black;
}

그래서 해당 css는 위 코드처럼 바뀌게 된다. 그렇다면 tag 선택자를 사용해야하는데, 그러기엔 tag가 범용적으로 사용되어 위험도가 높다.

해결방법

:global()

css modules에서 이 문제를 해결하기 위해 :global() 이라는 가상 선택자를 제공한다.

styles

.table {
  border: solid 1px black;
}

.table :global(.tableRow):not(:last-child) {
  border-bottom: solid 1px black;
}

이렇게 작성하면 클래스에 해쉬값을 붙여 재 생성하지 않는다. 하지만 그 의미는, 클래스 명이 중첩될 수 있다는 뜻이기 때문에 겹치지 않도록 클래스명을 신중하게 작성해야 한다.

profile
Front 💔 End

0개의 댓글