본문 바로가기

업무이야기

CSS BEM방식으로 Class명 만들기, BEM class naming

 

오늘은 현재 프로젝트에서 사용하고 있는 BEM으로 class명을 만드는 방법을 포스팅해보려고 합니다. 현재 제가 하고 있는 프로젝트에서 이 방식을 이용하고 있기 때문에 한번 공부해두면 도움이 될 것 같아서, 그리고 미래의 저를 위해서라도 정리해 두면 좋을 것 같아서 정리를 해두려고 합니다.

 

BEM 방식이란?

 

Block

Eelement

Modifier의 

약자입니다.

 

그리고 

list--star

list--dot

list__item

이런 식으로 '--', '__', '_'를 사용하는 것이 특징입니다.

그럼 어떤 상황에서 '--', '__' 및 '_' 를 사용하는지를 포함해서 BEM의 가이드라인에 따른 class이름 짓기를 알아보겠습니다.

 

Block

여기서 Block이란 '재사용'을 목적으로 '독립적'으로 사용될 수 있도록 하는 것이 요지입니다. 

Block에 맞게 class이름을 정하는 방법은 아래와 같습니다.

Block의 첫 번째 특징은 블록의 기능이나 목적으로 작명되어야 하며 시각적 특징으로 상태를 설명하지 않는 것입니다. 핵심 요지는 '이것이 무엇으로 보이는지'가 아닌 '이것이 무엇인지'가 목적이어야 합니다.

 

제가 생각하기엔 '이것이 무엇으로 보이는지'가 '이것이 무엇인지'에 포함된다고 생각합니다.

 

포함 관계도를 그려보자면 '이것이 무엇으로 보이는가' ⊂ '이것이 무엇' 이렇게 됩니다. 

가령 '허리가 길고 다리가 짧다'라는 설명이 닥스훈트를 틀리게 설명하고 있는것인가? ('허리가 길고 다리가 짧다' ⊂ '닥스훈트') 라고 묻는다면 그것은 아닙니다 . 하지만 BEM의 룰에 따르면 Block요소 (부모)는 class="long-waist" 혹은 class="short-legs"가 아닌 class="hound"(사냥개) 혹은 class="dachshund"(닥스훈트)가 되지 않을까 싶습니다.  

 

따라서 클래스 명을 정할 때 '무엇으로 보이는지'에 대한 것을 제외하고 '기능이나 목적'에 집중을 한다면 그것이 block사용법에 맞는 class명이 되지 않을까 생각합니다.

 

예를 들어서 '보장내용'을 설명하는 파란색 bg인 박스를 여러 번 써야 할 때 class naming을 해보자면 

Block에 적합 ▼

class="guarantee-box" 혹은 class="guarantee-info" 

Block에 부적합

class="blue-round-box" 

 

Block의 두 번째 특징은 '중첩'입니다. 여기서 중첩이란 Block안에 Block이 있는 형태를 의미합니다. 

1
2
3
4
5
6
7
<!-- guarantee-box Block --> 
<div class="guarantee-box"> 
    <!-- desc Block --> 
    <p class="desc">보험상품 보장내용에 관한 설명입니다.</p> 
    <!-- criterion Block --> 
    <p class="criterion">보험상품 기준에 관한 설명입니다.</p> 
</div>
cs

위의 예시에서는 guarantee-box블록 안에 desc와 criterion 두 개의 블록이 포함된 형태를 '중첩'이라고 말합니다. 

보통 다음 두 번째 요소인 Element에서 설명할 것이긴 하지만  Block에 해당하는 자식 요소는 언더바 2개 '__'를 사용해서 표현합니다.

위의 예시를 연장해서 예 )

<p class="guarantee-box__desc">

<p class="guarantee-box__criterion">

이렇게 모든 자식 요소에 언더바 2개를 사용하다 보면 복잡한 요소의 경우에 class명이 굉장히 길어진다는 단점이 있습니다. 

위 태그는 p태그 이기 때문에 자식 요소가 없다는 점에서 언더바 2개를 사용하는 게 더 적합해 보이지만 복잡한 태그 구조일 경우에는 아래와 같이 class명이 굉장히 복잡해지는 문제가 생길 수 있기 때문에 '중첩'이란 특징이 꼭 필요해 보입니다.

 

중첩의 요소가 허용되지 않을 시 발생되는 문제점

1
2
3
4
5
6
7
<ul class="list">
    <li class="list__item">
        <div class="list__item__wrapper">
            <p class="list__item__wrapper__desc"></p>
        </div>
    </li>
</ul>
cs

 

Element (Block 요소처럼 기능이나 목적에 따라 작명, 중첩 허용)

 

Element 요소는 방금 위에서 언급했던 것처럼 Block이 포함하고 있는 자식 요소 두 개의 언더바'__' 전문용어로 underscore를 사용해서 class 이름을 정하는 방식입니다.

 

예)

<p class="guarantee-box__desc">

<p class="guarantee-box__criterion">

 

이렇게 사용하면 시각적으로 알아 보기 용이한 장점이 있습니다.

하지만, 자식 요소를 '__'를 사용해서 표기한다 해도 위의 "<p class="list__item__wrapper__desc"></p>"는 안 좋은 예입니다. Element의 계층구조(2 depth 이상)를 지양하기 때문입니다. Element는 1 depth까지 표현하는 것이 좋습니다. 

 

 

위의 3 depth naming 문제점을 중첩을 통해서 수정한 예

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- list Block -->
<ul class="list">
    <!-- list Element: list__item -->
    <li class="list__item">
        
        <!-- guarantee-box Block -->
        <div class="guarantee-box">
 
            <!-- guarantee-box Element: tuarantee-box__desc -->
            <p class="guarantee-box__desc"></p>
        </div>
    </li>
</ul>
cs

 

 

또한 가장 부모의 클래스명을 가지고 자손 관계 혹은 그 이상의 깊이도 상관없이 '__'을 사용하는 것을 허용하기 때문에 다음과 같이 class명을 지어줄 수도 있습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
<!-- guarantee-box Block -->
<div class="guarantee-box">
    <!-- guarantee-box Element: guarantee-box__wrapper -->
    <div class="guarantee-box__wrapper">
 
        <!-- guarantee-box Element: guarantee-box__desc -->
        <p class="guarantee-box__desc">
 
        <!-- guarantee-box Element: guarantee-box__criterion -->
        <p class="guarantee-box__criterion">
    </div>
</div>
cs

div안에 div안에 p태그가 있는 형태지만 모두 부모의 guarantee-box를 재사용해서 '__'(element방식)을 사용하여 자식 요소 class명을 지어줬습니다.

 

Modifier

Modifier은 Block과 Element와는 반대로 상태 또는 외양으로 속성을 정의합니다. '--' 또는 '_'로 표기됩니다. 제가 이번에 하는 프로젝트에서는 '--'의 형태를 사용했지만 포스팅을 하기 위해서 다양한 자료를 참고하던 중 '_'의 형태도 있다는 것을 알게 되었습니다. class="list"가 있고 Modifier의 속성을 이용하여 여러 type의 리스트를 만든다고 가정한다면 class="list--star", class="list--hypen", class="list--dot"로 class 이름을 지을 수 있겠습니다.

예)

 

*리스트1

*리스트2

 

-리스트1

-리스트2

 

ㆍ리스트1

ㆍ리스트2

 

scss ▼

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.list { 
    $root: '.list'; 
    margin: 0; padding: 0; list-style: none;
 
    &__item {
        padding-left: 15px;
 
        &::before {
            content:""; position: absolute; left: 10px;
        }
    }
    
    &.list--star {
        #{$root}__item::before { content: "*";}
    }
 
    &.list-- dot{
        #{$root}__item::before { content: "ㆍ";}
    }
 
    &.list-- hypen{
        #{$root}__item::before { content: "-";}
 
        }
    }
}

cs

 

html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ul class="list list--star">
    <li class="list__item">리스트1</li>
    <li class="list__item">리스트2</li>
</ul>
 
<ul class="list list--dot">
    <li class="list__item">리스트1</li>
    <li class="list__item">리스트2</li>
</ul>
 
<ul class="list list--hypen">
    <li class="list__item">리스트1</li>
    <li class="list__item">리스트2</li>
</ul>
cs

 

이렇게 포스팅을 해보니 실제 업무에서 쓰였던 태그들과 클래스 이름을 한번 더 고민해보게 되고 공부가 많이 되는 것 같습니다. 업무를 하다 보면 아무리 경력이 많으신 과장님이시더라도 class명을 만들 때 한참 고민하시는 모습을 많이 보게 됩니다. 저 또한 프로젝트를 경험하면 할수록 같이 작업할 때 코드에 통일성의 중요성에 대해서 더 깨달아 가고 있는 중입니다.

 

 

반응형