CSS의 클래스 네임을 작성하는 일은 상당히 까다로운 일이다. 아무렇게나 작성해도 구동에는 무리가 없지만, 그렇게 되면 코드의 구조를 이해하기 어렵고 유지보수가 힘들어진다. 따라서 “최대한 의미있고 구조를 쉽게 파악할 수 있는 클래스 이름”을 작성하는 일이 중요한 것이다.

이 문제로 고민을 하던 중, CSS의 네이밍 컨벤션인 BEM을 알게 되었다.

BEM 개요

BEM 이미지

BEM은 CSS 클래스 이름을 위한 네이밍 컨벤션으로, 여러 웹 사이트에서 널리 채택되고 있는 방법론이다. BEM은 Block, Element, Modifier를 의미하며, 다음과 같이 표기한다.

.block__element--modifier

예를 들어, header__btn–home에서 header는 block, btn은 element, home이 modifier이다.

BEM은 원칙적으로 ID를 사용하지 않으며, class만을 사용한다. 그리고 ‘어떻게 보이는가’ 보다는 ‘어떤 목적인가’에 따라 이름을 짓는데, 예컨대 button의 모양(.red)보다는 기능(.stop)을 고려하여 이름을 짓는 식이다. 이름을 연결할 때는 케밥 케이스(-)를 사용하거나 카멜 케이스(대문자)를 사용할 수 있다.

BEM은 다음과 같은 세 가지 이점을 제공한다고 말할 수 있다.

BEM은 목적 또는 기능을 전달한다.
BEM은 구성 요소의 구조를 전달한다.
BEM은 선택자 특이성을 항상 낮은 수준으로 유지한다.

(NATHAN RAMBECK의 ‘BEM by Example’에서 인용)

BEM의 구성요소를 좀 더 살펴보면 다음과 같다.

1. Block

블록(Block)은 구성 요소의 가장 바깥쪽 상위 요소이다. 더 구체적으로 말하면,

재사용 가능한 기능적으로 독립적인 페이지 컴포넌트
(A functionally independent page component that can be reused)

즉, 어딘가에 종속되지 않으며 재사용할 수 있는 요소가 블럭이다. 그리고 블럭은 블럭을 감쌀 수 있다. 예를 들어 .block1 > .block2와 같은 식이다.

2. Element

엘리먼트(Element)는 블럭을 구성하는 단위이다. 엘리먼트는 블록과는 달리, 의존적인 특성을 갖는다. 즉, 상위 블럭 내에서만 의미를 가지므로 엘리먼트만을 떼어 다른데 사용할 수 없다.

3. Modifier

변경자(Modifier)는 블럭이나 엘리먼트의 속성을 의미한다. 스타일이 약간 다르거나, 다르게 기능하는 블럭 또는 엘리먼트에 사용한다.

BEM 예제

구체적인 예제를 통해 BEM을 이해해보자.
BEM을 사용할 때 자주 간과되는 규칙을 중심으로 살펴보겠다.

1) 단일 요소와 단일 클래스만으로도 블록이 될 수 있다.

<!-- 단일 요소인 box는 블록이다 -->
<div class="box"></div>

2) 구성 요소에 변형이 있는 경우, 변경자 클래스를 사용한다.

<!-- box에 --red 변경자를 추가해서 확장 -->
<div class="box box--red"></div>

이때 변경자 클래스만 사용해서는 안 되며, 기본 클래스를 유지해야 한다. 아래는 틀린 사례이니 주의가 필요하다.

<!-- INCORRECT. 기본 클래스인 box를 유지해야 한다-->
<div class="box--red"></div>

3) HTML의 하위 요소에서 클래스 이름을 생략해서는 안 된다.

<!-- CORRECT -->
<div class="box">
  <img class="box__img" src="sample.jpg">
  <button class="box__btn"></button>
</div>

<!-- INCORRECT -->
<div class="box">
  <img src="sample.jpg">
  <button></button>
</div>

4) BEM 클래스 이름은 기본 블록 이름과 하나의 요소 이름만 허용한다.

<!-- CORRECT -->
<ul class="menu">
  <li class="menu__list">
    <a class="menu__item" href="#"></a>
  </li>
</ul>

아래와 같이 여러 개의 블록을 표기하여 각 수준을 나타내려고 하면 안 된다. BEM은 구조의 깊이를 전달하지 않는다. 이는 자주 간과되는 규칙 중 하나이다.

<!-- INCORRECT -->
<ul class="menu">
  <li class="menu__list">
    <a class="menu__list__item" href="#"></a>
  </li>
</ul>

5) BEM은 케밥 케이스 또는 카멜 케이스와 접목할 수 있다.
둘 중에 무엇을 사용하든 괜찮지만, 혼용해서는 안 된다.

<!-- 케밥 케이스 -->
<nav class="nav-container">
  <ul class="topMenu">
    <li class="topMenu__list"></li>
  </ul>
</nav>

<!-- 카멜 케이스 -->
<nav class="navContainer">
  <ul class="topMenu">
    <li class="topMenu__list"></li>
  </ul>
</nav>

마치며

BEM의 기본 규칙들을 공부하고 나서 프로젝트에 적용해 보았다. 과연, 클래스 네임을 작성하는 일이 한결 쉬워졌으며 자신감이 생겼다. 네이밍의 명확한 기준이 확립되었기 때문이라고 생각한다.

한편, HTML 문서의 가독성이 높아졌을 뿐만 아니라, CSS에서 셀렉터를 선언하는 작업이 매우 쉬워졌다. 태그 간의 구조를 고민할 필요 없이, 작성한 클래스 네임을 그대로 사용하면 되기 때문이다. 덕분에 작업 시간이 크게 단축되었다.

BEM의 유용성을 스스로 경험해보니 그 효과가 놀라울 정도이다. 덕분에 퍼블리싱 실력이 크게 늘어난 것 같아서 무척이나 감사한 마음이다. 사랑해요 BEM.

참고자료

예제로 이해하는 BEM : https://naradesign.github.io/bem-by-example.html
https://nykim.work/15

(글에서 틀린 것이 있다면 꼭 지적해 주세요. 감사히 배우겠습니다)