본문으로 바로가기

BEM(Block Element Modifier) 방법론

category StyleSheet/CSS 2016. 1. 5. 09:07

BEM 방법론

대개 우리는 우리가 작성하는 코드가 읽기 쉬웠으면 합니다. 그렇게 되면 더 빨리 그리고 더 효율적으로 일을 하는데 도움이 되고, 다른 개발자가 합류한다 하더라도 명확성과 일관성 있는 의미론을 유지할 수 있기 때문입니다. 

요즘에는 CSS세계(OOCSS, SMACSS, BEM 등)에 표준도 많고 그에 따른 용어들도 아주 많은 것 같습니다. 

다 이러한 것들이 CSS 구조를 개선시키기 위한 CSS 개발 방법론인데 이 방법론 중에 BEM 방법론을 알아보겠습니다.

BEM은 Block Element Modifier의 약자입니다. 

이것은 문제의 요소에 대한 속성에 근거하는 클래스의 이름을 짓는데 구조적인 방법을 제시한다. 

만약 header__form--email과 같은 클래스명을 본적이 있다면, 그렇다! 이것이 바로 BEM 방법론을 활용한 것입니다. 

BEM 방법론은 ID에는 사용할 수 없고, 오직 클래스명에만 활용할 수 있다는 점에 주의해야 합니다. 

필요하다면, 클래스명은 BEM방식의 이름을 여러번 반복하여 재사용할 수 있도록 허락하며, HTML과 CSS/Sass 파일에서도 더 일관된 코딩 구조를 만듭니다.





Block(전체를 감싸고 있는 블럭요소)

블럭(block)은 문단 전체에 적용된 요소 또는 요소를 담고 있는 컨테이너를 말합니다. 보다 더 큰 구조적인 코딩의 덩어리로 생각하세요. 

헤더, 풋터, 사이드바, 그리고 메인 컨텐츠 영역을 가지고 있다고 가정하면, 이 각각의 영역들이 블럭으로 간주되는 것입니다. 

아래의 그림을 참조하세요



블럭 요소는 클래스의 어근을 형성하고 항상 맨 앞에 위치하도록 합니다. 

일단 블럭을 정의하면, 블럭이 형성한 클래스의 어근을 맨 앞에 붙여 그 블럭이 포함하는 요소들의 클래스명을 짓기 시작하면 되는 것입니다.




Element

요소(element)는 블럭이 포함하고 있는 한 조각입니다. 

블럭은 전체를 말하고 요소들은 그 조각들을 일컫고 각 요소는 두개의 밑줄표시(underscore)로 연결하여 블럭 다음에 위치시킵니다.

css
.block__element { property: value; }

좀 이상하게 보일지 모르겠지만, 일단 이렇게 사용하기 시작하면 이 방법론의 매력(?)에 빠져들 것 입니다. 

두개의 밑줄표시는 시각적으로 쉽게 그리고 빨리 코드를 찾고 조작할 수 있도록 도와줍니다.

아래의 것은 이 방법론이 실질적으로 어떻게 적용되는지 보여주는 예입니다.

css
.header__logo { property: value; }
.header__tagline { property: value; }
.header__searchbar { property: value; }
.header__navigation { property: value; }

보면 알 수 있듯이, 이를 더 창의적으로 활용할 수도 있고, 이 방법론을 자신의 것으로 만들 수 있는 여지가 충분히 남아 있습니다. 

‘navigation’은 ‘nav’로, ‘tagline’은 ‘tag’ 또는 ‘tagLine’으로 수정 가능하다는 것입니다. 

여기서 요점은, 클래스명은 간단하고 명확하며 정확하게 유지해야 한다는 것으로 너무 고민하지 않도록 합니다. 

스타일시트와 HTML 역시 DRY(don’t repeat yourself)로 유지되어야 하기 때문입니다. 

더 나은 의미론적인 방식을 찾았을때 클래스명을 업데이트 시키는데는 문제가 없어야 합니다. 

그리고 요소들은 어떻게 스타일시트를 구조화하고 어떻게 레이아웃을 다룰지 생각하도록 도움을 주는 클래스명의 핵심이 된다.



Modifiers

modifier은 블럭 또는 요소의 속성입니다. 이 속성은 블럭 또는 요소의 외관이나 상태를 변화시키는 것 입니다. 

클래스명을 지을때의 목적은 그 요소를 반복하여 재사용할 수 있게 하기 위한 것이어서 요소의 스타일이 같은 것이라면 사이트의 다른 영역이라 할지라도 새로운 클래스를 정의하지 않아도 됩니다. 

특정 요소의 스타일을 수정할 필요가 있을때, 물론 modifier만 활용하면 됩니다. 

이렇게 하기 위해서는 요소 또는 블럭 다음에 두개의 하이픈(‘‐‐’)을 추가하여 modifier을 표시합니다. 

간단한 예는 다음과 같습니다.

css
.block‐‐modifier {…}
.block__element‐‐modifier {…}

주의해라! 모든 이름은 간단 명료해야 합니다. 

그리고 절대적으로 필요하지 않는 이상, 추가적인 클래스를 만들거나 똑같은 스타일을 반복해서는 안됩니다. 


header 블럭을 사용하는 코드를 가지고 이에 대해 이야기 해봅니다.

css
.header__navigation {…}
.header__navigation‐‐secondary {…}

만약 부차적인 네비게이션을 사용한다면, 아마도 레이아웃과 여백은 같을 것이나 적용되는 색이 다를 것입니다. 

우리는 메인 요소의 스타일을 복제하거나 훨씬 더 좋은 전처리 장치를 활용할 수 있으며 바로 Sass의 @extend 활용으로 부차적인 네비게이션은 메인 요소의 모든 속성을 상속받도록 할 수 있습니다.

그리고 그것들을 우리는 적절한 스타일로 수정하여 적용할 수 있습니다.

css
.header__navigation { 
      background: #008cba; 
      padding: 1rem 0; 
      margin: 2rem 0; 
      text-transform: uppercase; 
 } 
     
.header__navigation‐‐secondary { 
      @extend .header__navigation;
      background: #dfe0e0; 
 }

“하지만 클래스명이 너무 길다.”라고 생각할지 모르겠습니다. 

필자의 생각은, BEM 클래스명은 구체적이고 명료하며 HTML 안에서도 읽기 쉬워야 하고, 클래스명이 무엇을 나타내는지 분명하게 전달 되어야 한다 라는 것입니다. 

BEM 클래스명을 좋아하는 이유는 각 html 태그에 오직 클래스명 하나만 사용해야 한다는 것입니다. 

labels을 예로 어떻게 활용되는지 살펴 보겠습니다. 

일반적으로 사용하는 선택자는 다음과 같습니다.

css
.label .label-default {...} 
.label .label-alert {...}


다음은 BEM 방법론을 활용한 선택자 방식입니다.

css
.label {...}
.label‐‐alert {...}

간단한 예로, 우리가 위에서 정의했던 label에 다음과 같은 스타일을 줄 수 있다.

css
.label { 
      background: #eee; 
      border-radius: 505; 
      color: #333; 
      font-size: 1rem; 
 } 
     
.label--alert { 
      background: #da4531; 
      color: #fff; 
 }





요점

  • HTML 마크업 모듈화 
  • block요소를 독립적이고, 재사용 가능한 모듈이라는 개념으로 접근 
  • 대표적인 사이트 tuts+ 
  • 예).block(전체를 감싸고 있는 블록요소)__element(내부 요소)--modifier(기능) 
  • prefix 붙여 일종의 네임스페이스개념으로 사용 
  • 실제 서비스를 하면 HTML의 구조가 바뀌는 일이 다반사 
  • 탐색레벨은 낮고 단순하게 유지하는 것이 유지보수하기 좋음 
  • 최근 브라우저 테스트 자동화에 대한 요구가 커지고 있음 
  • 쿼리를 단순하게 하기 위해 길고 유니크한 클래스명을 사용하는 것이 좋음


장점

  • class name 중복을 방지한다.
  • 직관적이다 : .gnb__home--active .icon-home 
  • 전제 DOM tree 구조를 다시 보지 않아도 된다.


CSS속성은 한줄에 하나만 선언하자!

  • 가독성이 좋고 어느 속성을 어느 위치에 넣을 것인지 고민할 필요가 없어진다. 
  • diff 할 때 가독성이 뛰어나다. 
  • 빌드시에 minify하는 전략에 효과적이다.


BEM 사용 예제

html
<div class="media">
    <img src="logo.png" alt="Foo Corp logo" class="media__img--rev">
    <div class="media__body">
        <h3 class="alpha">Welcome to Foo Corp</h3>
        <p class="lede">Foo Corp is the best, seriously!</p>
    </div>
</div>
css
.media { ... }
.media__img--rev { ... }
.media__body { ... }


클래스 header 안에 정의된 요소들을 정의한다면 아래와 같이 작성할 수 있습니다.

css
.header__logo {} 
.header__tagline { ... } 
.header__searchbar { ... }
.header__navigation { ... }
.header__navigation { ... }
.header__navigation--secondary { ... }




마치며

아주 간결한 BEM! 이미 알겠지만, BEM은 훨씬 진화된 시스템입니다. 

이것은 우리가 작성하는 코드에 명료함을 가져다 주고, 더 잘 정의할 수 있도록 도와주며, 프론트 엔드 개발면에서 분류의 체계를 설정할 수 있도록 만듭니다. 

많은 경험자들에 의하면, BEM 방법론은 프로토타입을 더 효율적으로 만들어 제품 수준의 코드로 빨리 전환하는데 엄청나게 도움을 준다고 합니다.





Jaehee's WebClub