[CSS] 네이밍 컨벤션 BEM
프론트앤드, 특히 css 쪽에서 자주 사용하는 BEM (Block Element Modifier) 방법론에 대해서 정리하려 합니다.
BEM은 전체적으로 이렇게 이루어집니다.
- 항상 영어 소문자만을 사용합니다. 카멜 케이스 등은 사용하지 않습니다.
- 일반적으로 한 요소는 하이픈으로 연결합니다. (예를 들면 input-text, button-submit, modal-alert 등등.. )
- 네이밍의 조합은 형태-의미-순서-상태 순으로 사용합니다. (예시 button-submit-03-disable)
- 언더스코어는 파일, 폴더, 이미지 등에만 사용합니다(image_elysia_asset_01.png)
- 숫자를 사용할 때는 확장성을 고려해 1, 2 이런 식으로 표현하지 않고 01, 02, 03… 혹은 001, 002, 003처럼 사용합니다. 앞에 0을 붙이지 않으면, 이미지 정렬 시 1 다음에 2가 오지 않고 10이 오는 등, 정렬 순서가 엉망이 될 수 있기 때문입니다.
BLOCK
여기서 Block은 문단 전체에 적용되는 요소, 혹은 그 요소를 담고 있는 큰 덩어리입니다.
이 Block들은 클래스의 컴포넌트를 형성하고, 항상 맨 앞에 위치합니다. 여기서 이 클래스의 이름을 정의할 때는, 해당 Block의 목적을 기술해야 하며, 이 Block 자체의 형태 등을 고려하지는 않습니다.
- 옳은 예시
button, header, modal, textarea 등 이것이 무엇인가? 에 대해 목적을 알 수 있는 적절한 이름
<button class="button"> ... </button><header class="header"> ... </header><div class="modal"> ... </div><textarea class="textarea"> ... </textarea>
- 틀린 예시
red-text, big-radio-button, #0000FF-awesome-thing 등 자체의 형태는 사용되지 않습니다.
<p class="red-text"> ... </p><input type="radio" class="big-radio-button"> ... </input><button class="deep-blueable-awesome-thing"> ... </button>
이 Block은 환경에 영향을 받으면 안 됩니다. 이를테면, margin을 넣거나 position으로 top, left 값을 조절하는 등 여백이나 위치를 설정하면 안 됩니다.
이를 통해, Block을 재사용하거나 위치를 변경하는 등 Block의 독립성을 보장합니다.
Block은 서로 중첩해서 사용할 수 있으며, 여러 번 중첩해서 사용할 수 있습니다.
- 예시
<header class="header">
<div class="logo">
<img class="image" />
</div>
<textarea class="textarea"></textarea>
</header>
Element
Block이 포함하고 있는, Block에서 별도로 사용할 수 없는 한 Block을 이루고 있는 부분입니다.
Block이 전체라면, Element들은 조각을 일컫습니다. 해당 Element는 두 개의 underscore로 표시합니다.
.block-name__element-name { ... }
여기서 두 개로 표시하는 이유는, 기존 Block 이름 자체에 하이픈 및 언더바가 사용될 수 있으므로, 기존 네이밍과 혼동하지 않도록 두 개로 표기해서 가독성을 살리기 위함입니다.
- 예시
<div class="qna-form">
<p class="qna-form__text">
....
</p>
<div>
Element는 서로 중첩할 수 있으며, 여러 중첩 수준을 가질 수 있습니다.
여기서 Element는 항상 다른 Element가 아니며, Block의 일부분입니다. 다른 Element의 부분으로 사용할 수 없습니다.
그리고 Block에는 Element가 없을 수도 있습니다. Block에 Element는 반드시 들어가야 하는 건 아니며 선택적으로 사용할 수 있습니다.
- 예시
<form class="search-form">
<div class="search-form__content">
<input class="search-form__input">
<button class="search-form__button">Search</button>
</div>
</form><!-- 이렇게 다른 Element의 Element로는 사용하면 안 됩니다. -->
<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>
Modifier
Block 혹은 Element의 형태. 즉, 모양(color, size … ) 이나 상태 (focusing, disable,) 행동 (showing, enable) 등을 정의하며, 하이픈 두 개로 표현합니다. ( — )
Block 에 바로 붙여서 사용할 수도 있고, Block의 Element에 붙여서 길게 사용할 수도 있습니다. 여기서 중요한 건 항상 Block의 일부여야 하며, 단독으로 사용해서는 안 됩니다.
- 예시
.block__element--modifier { ... }.block--modifier { ... }
여기서 Modifier에는 boolean 타입과 key-value 타입이 있습니다.
만약 Modifier를 boolean으로 표시한다면 기본적으로 값이 true라고 가정하며, key와 value를 표시할 때는 하이픈으로 연결해서 사용합니다.
- 예시
<!-- 굳이 enable을 지정하진 않고, 따로 Modifier를 붙이지 않습니다 -->
<div class="modal__button--disable"> </div><!-- 키와 값을 하이픈으로 연결합니다 -->
<div class="image--theme-ocean"> </div><div class="button--color-deep-blueable"> </div>
BUT?
이렇게 정리했지만 사실 css에서 모든 부분에서 BEM이 사용되지는 않습니다.
BEM은 뭔가 엄청 복잡해 보이고 이상해 보이는 건 사실입니다. 하지만 그만큼 가독성이 뛰어나며, 효과적으로 대상을 지칭할 수 있게 됩니다.
하지만, 다음과 같은 상황에서는 굳이 억지로 사용할 필요는 없습니다.
- 예시 1
p,
a,
span {
font-family: "NotoSansKr", "Inter";
}.bold {
font-family: "NotoSansKr-Bold", "Inter-Bold";
}
위와 같은 상황은 굳이 세분화하지 않아도 그냥 이대로 있는 거라 어떻게 할 수도 없고, 억지로 할 필요도 없습니다.
오히려 header__text — bold 이런 식으로 하나하나 잡아 늘인다면 손이 많이 가고 괜히 귀찮아지기만 하게 됩니다. 의미 없는 건 덤이지요.
- 예제 2
.elysia-logo { ... }
그냥 로고를 넣은 클래스입니다. 만약 이걸 BEM으로 표현한다면,
.header {}
.header__logo {}
이렇게 변하게 됩니다. BEM 기법은 언제 어떤 것이 연관성 있게 묶였는가를 파악하는 것입니다.
그냥 어쩌다 보니 블록 안에 들어있다고 해서 모두 BEM 요소가 되는 것은 아닙니다. 지금 이 로고는 header에 우연히 들어와 있었을 뿐, 나중에 사이드바로 가거나 푸터로 갈 수도 있습니다. 이 요소들의 범위에는 어떤 맥락으로든 시작할 수 있어, 꼭 필요한 곳에 적용해야 합니다.
<div class="content">
<h1 class="content__headline"> ... </h1>
</div>
여기서 우리는 저것을 그냥 .headline이라고 지을 수도 있습니다. 여기서 중요한 건 저 headline이 .content 안에 있어서 특정한 css를 유지하는지, 아니면 그냥 우연히 content 안에 들어와 있는 것인지를 꼭 확인해야 합니다. 물론 후자라면, BEM을 사용할 이유가 없습니다.
출처 : Elysia TechBlog
'HTML - CSS - 웹표준' 카테고리의 다른 글
[CSS] 가상 클래스 셀렉터 :nth-child와 :nth-of-type의 차이점 (0) | 2023.03.02 |
---|---|
[CSS] 네이밍 규칙 (0) | 2023.02.24 |
[CSS] 가상 요소 "::before"와 "::after" 완벽 정리 (0) | 2023.01.27 |
[CSS] 반드시 기억해야 하는 선택자 30개 (0) | 2023.01.16 |
[CSS] 선택자(Selector) 이해 (0) | 2023.01.12 |