프론트엔드 css 정리 [part 5] | BEM

27933 단어 htmlCSSCSS

html과 css의 기본 사용법을 익혔다면 필요한 내용이므로 정리합니다.
참고 사이트


BEM

별거 아니라 생각할 수 있지만 중요한 네이밍 규칙으로 selector를 보고 어떤 역할을 혹은 무엇을 의미하지는 알 수 있어야 합니다.

당연히 코드는 내가 아닌 다른 이가 보더라도 이해하기 쉽고 읽기 쉬운 코드가 좋습니다.
그러면 자연스럽게 팀의 효율은 저절로 올라가며 규칙적이고 명확한 코드는 소통 및 유지보수에도 유리할 것입니다.

BEM | Block Element Modifier 기법은 블럭, 요소, 수식어 기반의 css 개발 방법론입니다.

기본 구조

  • BEM 방법론은 id, tag 등...을 사용하지 않고 오직 class만 활용할 수 있습니다.
  • BEM 방법론에서 이름을 연결할 때는 block-name과 같이 하이픈 하나로 연결합니다.

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

block 요소는 class의 어근을 형성하기 때문에 항상 맨 앞에 위치합니다.

문단 전체에 적용된 요소 혹은 요소를 담고 있는 컨테이너를 의미합니다.

대표적으로 header, nav, footer...를 예시로 들 수 있지만 layout을 위한 요소라고 생각하기 보단 독립적인 하나의 컴포넌트를 생각하면 됩니다.

그렇기 때문에 블럭의 네이밍은 상태가 아닌, 기능에 목적을 두고 정해야 합니다.

예를 들어 에러 메세지를 띄우고 싶다면 어떤 상태인지 혹은 어떻게 보이는지가 아닌 어떤 기능인지 확인할 수 있어야합니다.

/* O */
<div class="error"></div> 

/* X */
<div class="red-text"></div> 

Example

[로그인 폼] (or [검색 창], [메인 영역], [사이드 영역] 독립적이며 재사용 가능한 하나의 컴포넌트라면 무엇이든 될 수 있습니다.)이라는 하나의 블럭은 헤더에 혹은 사이드에 어디든 사용할 수 있습니다. 그렇기 때문에 block 요소를 우리는 기능이 독립적이며 재사용이 가능한 모듈이라는 개념으로 생각할 수 있습니다.

Block 특징

  • 위의 규칙을 고려했을 때 블럭은 외부 환경에 영향을 받으면 안됩니다.
  • 어디든 사용할 수 있어야 하며 독립적인 모듈이기 때문에 margin, padding 혹은 위치 등을 설정해서는 안됩니다.
  • 블럭의 내부에 다른 블럭을 불러올 수 있습니다. 자식을 가질 수 있다는 의미입니다.
<!-- `header` block -->
<header class="header">
    <!-- Nested `logo` block -->
    <div class="logo"></div>

    <!-- Nested `search-form` block -->
    <form class="search-form"></form>
</header>

즉, 블럭은 하나의 컴포넌트로써 재사용이 가능하며 다른 요소들에게 종속되지 않을 경우 블럭으로써 사용할 수 있습니다.


Element | 블럭이 포함하는 요소

블럭은 독립적인 모듈의 개념이지만 엘리먼트는 의존적인 개념입니다. 그렇기 때문에 블럭 전체를 따로 사용할 수는 있지만 엘리먼트만 가져와 따로 사용할 수는 없으며 엘리먼트는 항상 블럭의 자식(엘리먼트는 항상 블럭에 의존되어야 한다는 의미)이여야 합니다.

<!-- O -->
<form class="search-form">
  <input class="search-from__input">
  <button class="search-from__button">Button</button>
</form>

<!-- X -->
<form class="search-form">
  <button class="search-from__button">Button</button>
</form>
  
<input class="search-from__input">

또한 엘리먼트는 어떻게 보여지는지, 어떤 상태인지는 중요하지 않습니다.
엘리먼트가 의미하는게 무엇인지 정확한 목적에 따라 기술되어야 합니다.

  • 엘리먼트가 의미하는 바가 무엇인지? ⭕
<div class="header">
  <h1 class="header__title">title<h1>
</div>
  • 엘리먼트가 어떤 상태 혹은 모양인지? ❌
<div class="header">
  <h1 class="header__big">title<h1>
</div>

Element 특징

  • 엘리먼트들은 얼마든지 중첩이 가능합니다.
  • 엘리먼트들은 항상 블럭의 자식으로써 사용(블럭에 의존)됩니다.
<!-- ⭕ -->
<form class="search-form">
    <div class="search-form__content">
        <input class="search-form__input">
        <button class="search-form__button">Search</button>
    </div>
</form>

search-form이라는 블럭의 자식으로 search-form__content가 들어가 있고 search-form__content의 자식으로 search-form__input, search-form__button가 있지만 엘리먼트의 자식이 아닌 블럭의 자식(의존)으로 사용됩니다.

<!-- ❌ -->
<form class="search-form">
    <div class="search-form__content">
        <!-- 아래의 엘리먼트들은 엘리먼트의 자식으로 활용되고 있습니다. -->
        <input class="search-form__content__input">
        <button class="search-form__content__button">Search</button>
    </div>
</form>

엘리먼트가 블럭의 자식(블럭에 의존)으로 사용된다면 (위의 엘리먼트 규칙을 지키며 사용한다면) 아래와 같은 형식은 문제가 없습니다.

<!-- case 1 -->
<div class="block">
    <div class="block__elem1">
        <div class="block__elem2">
            <div class="block__elem3"></div>
        </div>
    </div>
</div>

<!-- case 2 -->
<div class="block">
    <div class="block__elem1">
        <div class="block__elem2"></div>
    </div>

    <div class="block__elem3"></div>
</div>

블럭안의 엘리먼트들의 구조가 변경되어도 이들의 규칙은 모두 유지되며 모든 케이스에 대한 css 코드는 아래와 같이 동일한 결과를 가져옵니다.

.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}

물론 모든 블럭 요소들이 엘리먼트를 가져야할 필요는 없습니다.

<!-- `search-form` block -->
<div class="search-form">
    <!-- `input` block -->
    <input class="input">

    <!-- `button` block -->
    <button class="button">Search</button>
</div>

클래스의 이름은 간단하지만 명확해야 합니다.
navigation을 nav 등으로 사용해도 되지만 혼자만 알 수 있는 네이밍 보다는 누가 보더라도 확실한 네이밍이 중요합니다.


Modifier | 블럭 혹은 엘리먼트의 속성

모디파이어는 블럭 혹은 엘리먼트의 속성을 담당합니다.

그렇기 때문에 모디파이어는 단독으로 사용할 수 없고 블럭이나 엘리먼트의 모양, 상태, 동작을 변경하거나 다르게 동작할 때 사용됩니다. ex) focused, disables, size-s, color...

Example

modifier case 1 | Boolean

블럭 혹은 엘리먼트의 모양, 상태, 동작에 대한 값은 필요없고 참, 거짓만으로 판단할 수 있을 때 불리언 타입을 사용합니다. 이때 항상 참(true)의 값이라고 가정하고 사용합니다.

  • block-name_modifier-name
  • block-name__element-name_modifier-name
<!-- 아래는 입력의 대한 값은 필요없습니다. 단지 입력창이 포커스 되어 있는지 참, 거짓만을 판단합니다. 즉, 입력창에 포커스가 참일 경우라고 생각할 수 있습니다.-->
<form class="search-form search-form_focused">
    <input class="search-form__input">
  
    <!-- 마찬가지의 경우입니다. 버튼 활성화의 참, 거짓을 판단하며 참의 값을 사용하기 때문에 비활성화된 버튼을 의미합니다. -->
    <button class="search-form__button search-form__button_disabled">Search</button>
</form>

modifier case 2 | Key-Value

반면 값이 필요할 경우 키와 값을 페어로 사용합니다.

  • block-name_modifier-name_modifier-value
  • block-name__element-name_modifier-name_modifier-value
<!-- search-form 블록에는 'islands' 값이 있는 'theme' 모디파이어가 있습니다. -->
<form class="search-form search-form_theme_islands">
    <input class="search-form__input">

    <!-- '버튼' 엘리먼트는 'm' 값이 있는 '사이즈' 모디파이어가 있습니다. -->
    <button class="search-form__button search-form__button_size_m">Search</button>
</form>

<!-- 값이 다른 두 개의 동일한 모디파이어를 동시에 사용할 수 없습니다. -->
<form class="search-form
             search-form_theme_islands
             search-form_theme_lite">

    <input class="search-form__input">

    <button class="search-form__button
                   search-form__button_size_s
                   search-form__button_size_m">
        Search
    </button>
</form>

part 6에서 계속...

좋은 웹페이지 즐겨찾기