BEM이 유용하다는 것은 알겠지만 막상 적용하려 하니 어려운 게 한두 가지가 아니다.
그래서 검색을 좀 해봤는데 좋은 글이 영어로 있어 번역을 해두려 한다.
번역기 돌려서 조금 다듬는 정도지만

원문: Battling BEM CSS: 10 Common Problems And How To Avoid Them

1. 자손 선택자의 경우 어떻게 해야 하나요?

두 수준으로 중첩된 요소를 참조해야 할 때 자손 선택자를 사용할 것입니다. 이 녀석들은 내 인생의 골칫거리이고, 나는 자손선택자의 오용이 사람들로 하여금 BEM에 즉시 혐오감을 갖게 하는 이유 중 하나라고 확신합니다. 예를 들어보죠.

<div class="c-card">

    <div class="c-card__header">
        <!-- Here comes the grandchild… -->
        <h2 class="c-card__header__title">Title text here</h2>
    </div>

    <div class="c-card__body">

        <img class="c-card__body__img" src="some-img.png" alt="description">
        <p class="c-card__body__text">Lorem ipsum dolor sit amet, consectetur</p>
        <p class="c-card__body__text">Adipiscing elit.
            <a href="/somelink.html" class="c-card__body__text__link">Pellentesque amet</a>
        </p>

    </div>
</div>


이런 식으로 네이밍하는 것은 금세 통제할 수 없게 되며 구성 요소가 더 많이 중첩될수록 클래스 이름이 더 끔찍하고 읽기 어렵게 됩니다. 나는 c-card라는 짧은 블록 이름과 body, text, link와 같은 짧은 요소 이름을 사용했지만, 만약 첫 번째 블록 요소가 c-drop-down-menu와 같다면 어떻게 될지 상상할 수 있을 것입니다.

이중 하이픈(--) 패턴은 선택자 이름에 한 번만 나타나야 한다고 생각합니다. BEM은 Block__Element–Modifier를 의미하지, Block__Element__Element–Modifier를 의미하는 게 아닙니다. 따라서 여러 요소를 중첩해 네이밍 하는 것을 피하십시오. 증증증증손자 수준에 도달했다면 어쨌든 컴포넌트 구조를 다시 방문하고 싶을 것입니다.

BEM 네이밍은 DOM에 엄격하게 연결되어 있지 않으므로 하위 요소가 중첩된 수준의 깊이는 중요하지 않습니다. 명명 규칙은 최상위 컴포넌트 블록(이 경우 c-card)과의 관계를 식별하는 데 도움이 됩니다.

아래는 동일한 card 컴포넌트를 다루는 방법입니다.

<div class="c-card">
    <div class="c-card__header">
        <h2 class="c-card__title">Title text here</h2>
    </div>

    <div class="c-card__body">

        <img class="c-card__img" src="some-img.png" alt="description">
        <p class="c-card__text">Lorem ipsum dolor sit amet, consectetur</p>
        <p class="c-card__text">Adipiscing elit.
            <a href="/somelink.html" class="c-card__link">Pellentesque amet</a>
        </p>

    </div>
</div>

이것은 모든 하위 요소가 card 블록에 의해서만 영향을 받는다는 것을 의미합니다. 따라서 의미 구조를 깨뜨리지 않고 c-card__header로 이미지와 텍스트를 옮기거나 새로운 c-card__footer 요소를 추가할 수도 있습니다.

2. 네임스페이싱을 해야 합니까?

지금쯤이면 제 예시 코드 전반에 걸쳐 흩어져 있는 c-의 사용을 눈치채셨을 것입니다 . 이것은 '컴포넌트'를 나타내며 저의 BEM 클래스 네이밍의 기초를 형성합니다. 이 아이디어는 코드 가독성을 향상시키는 Harry Robert의 네임스페이스 기술에서 비롯되었습니다.

이것은 내가 적용한 시스템이며 이 글의 예시 코드 곳곳에 많은 접두사가 나타날 것입니다.

구분 접두사 설명
Component c- c-card,
c-checklist
어플리케이션의 중추를 형성. 독립적인 컴포넌트의 모든 외형적인 꾸밈요소(?)를 포함.
Layout module l- l-grid,
l-container
외형적 꾸밈요소 없이 c- 컴포넌트의 위치와 레이아웃만을 위함
Helpers h- h-show,
h-hide
보통 !important를 사용한 단일 기능 (일반적으로 위치나 가시 여부를 설정)
States is-,
has-
is-visible,
has-loaded
c- 컴포넌트가 가지는 다른 상태에 대한 세부 사항
JavaScript hooks js- js-tab-switcher 컴포넌트에 자바스크립트가 연동되었음을 의미. 어떤 스타일도 연동X.

이 네임스페이스를 사용하면 코드를 훨씬 더 읽기 쉽게 만들 수 있다는 것을 알게 되었습니다. 비록 당신이 BEM을 사용하지 않는다 하더라도, 이것은 확실히 중요한 포인트입니다.
qa-(품질 보증 테스트), ss-(서버 측 후크) 등과 같은 다른 많은 네임스페이스도 있습니다. 그러나 위에 언급한 것들은 좋은 시작점이며, 이런 기술에 익숙해지면 다른 네임스페이스도 사용할 수 있습니다.
다음 문제에서 이 네임스페이스의 유용성에 대한 좋은 예를 보게 될 것입니다.

3. 래퍼(wrapper)에는 어떤 이름을 붙여야 하나요?

일부 컴포넌트는 하위 레이아웃을 지시하는 상위 래퍼(또는 컨테이너)가 필요합니다. 저는 이러한 경우에는 항상 레이아웃을 l-grid와 같은 레이아웃 모듈을 통해 레이아웃을 따로 빼내고, 각가의 컴포넌트를 l-grid__item과 같이 삽입하고 있습니다.

우리의 card 예제에서 4개의 c-card 목록을 배치하려면 다음과 같은 마크업을 사용합니다.

<ul class="l-grid">
    <li class="l-grid__item">
        <div class="c-card">
            <div class="c-card__header">
                […]
            </div>
            <div class="c-card__body">
                […]
            </div>
        </div>
    </li>
    <li class="l-grid__item">
        <div class="c-card">
            <div class="c-card__header">
                […]
            </div>
            <div class="c-card__body">
                […]
            </div>
        </div>
    </li>
    <li class="l-grid__item">
        <div class="c-card">
            <div class="c-card__header">
                […]
            </div>
            <div class="c-card__body">
                […]
            </div>
        </div>
    </li>
    <li class="l-grid__item">
        <div class="c-card">
            <div class="c-card__header">
                […]
            </div>
            <div class="c-card__body">
                […]
            </div>
        </div>
    </li>
</ul>

이제 레이아웃 모듈과 컴포넌트 네임스페이스가 함께 작동하는 방법에 대한 확실한 개념을 잡아야 합니다.
엄청난 두통을 피하기 위해 약간의 추가 마크업을 사용하는 것을 두려워하지 마십시오. 아무도 당신의 <div> 태그 몇 개를 깎지 않을 것입니다!

어떤 경우에는 이것이 불가능합니다. 예를 들어, 그리드가 원하는 결과를 제공하지 않거나 단순히 부모 요소의 이름을 지정하는 의미론적인 것을 원하는 경우 어떻게 해야 합니까? 나는 상황에 따라 container 또는 list라는 단어를 선택하는 경향이 있습니다. 우리의 card 예로 본다면, <div class=“l-cards-container”>[…]</div>또는 <ul class=“l-cards-list”>[…]</ul>을 사용할 수 있습니다. 핵심은 명명 규칙과 일관되게 하는 것입니다.

4. 교차 컴포넌트… 컴포넌트?

일반적으로 직면하는 또 다른 문제는 스타일 또는 위치 지정이 상위 컨테이너의 영향을 받는 구성 요소입니다. Simurai는 이 문제에 대한 다양한 솔루션을 자세히 설명합니다. 제가 생각하기에 가장 확장 가능한 접근 방식에 대해 설명하겠습니다.

요약하자면, 우리가 이전 예시인 card__body에 c-button을 추가하려고 한다고 가정해봅시다. 버튼은 이미 자체 컴포넌트이며 다음과 같이 표시됩니다.

<button class="c-button c-button--primary">Click me!</button>

일반 버튼 컴포넌트에 스타일 차이가 없다면 문제가 없습니다. 우리는 그것을 다음과 같이 넣을 것입니다:

<div class="c-card">
    <div class="c-card__header">
        <h2 class="c-card__title">Title text here</h3>
    </div>

    <div class="c-card__body">

        <img class="c-card__img" src="some-img.png">
        <p class="c-card__text">Lorem ipsum dolor sit amet, consectetur</p>
        <p class="c-card__text">Adipiscing elit. Pellentesque.</p>

        <!-- Our nested button component -->
        <button class="c-button c-button--primary">Click me!</button>

    </div>
</div>

그러나 몇 가지 미묘한 스타일 차이가 있는 경우에는 어떻게 합니까? 예를 들어 c-card 컴포넌트의 일부일 때만 모서리를 완전히 둥글게 하여 크기를 조금 더 작게 만들고 싶을 때는요?
앞서 저는 교차 컴포넌트 클래스가 가장 강력한 솔루션이라고 말했습니다.

<div class="c-card">
    <div class="c-card__header">
        <h2 class="c-card__title">Title text here</h3>
    </div>

    <div class="c-card__body">

        <img class="c-card__img" src="some-img.png">
        <p class="c-card__text">Lorem ipsum dolor sit amet, consectetur</p>
        <p class="c-card__text">Adipiscing elit. Pellentesque.</p>

        <!-- My *old* cross-component approach -->
        <button class="c-button c-card__c-button">Click me!</button>

    </div>
</div>

이것은 BEM 웹사이트에서 "mix"로 알려진 것입니다. 그러나 나는 Esteban Lussich의 훌륭한 의견에 따라 이 접근 방식에 대한 입장을 바꾸었습니다.

위의 예에서 c-card__c-button 클래스는 c-button의 하나 이상의 기존 속성을 수정하려고 하지만, 성공적으로 적용하려면 소스 순서(또는 특정성)에 따라 달라집니다. 이 c-card__c-button 클래스는 c-button 소스 코드의 블록 뒤에 선언된 경우에만 작동하며, 이러한 교차 컴포넌트를 더 많이 만들면 빠르게 처리할 수 없게 될 수 있습니다. (물론 !important를 사용할 수도 있지만 권장하지는 않습니다!)

진정한 모듈식 UI 요소의 외형은 요소의 상위 컨테이너와 완전히 무관해야 하며, 어디에 놓아도 동일하게 보여야 합니다. "mix" 접근 방식과 같이 맞춤형 스타일링을 위해 다른 컴포넌트의 클래스를 추가하는 것은 컴포넌트 중심 설계의 개방형/폐쇄형 원칙에 위배됩니다. 즉, 미학을 위해 다른 모듈에 종속되어서는 안 됩니다.

가장 좋은 방법은 이러한 작은 외관상의 차이에 수정자를 사용하는 것입니다. 프로젝트가 발전함에 따라 다른 곳에서 재사용하고 싶을 수도 있기 때문입니다.

<button class="c-button c-button--rounded c-button--small">Click me!</button>

이러한 추가 클래스를 다시는 사용하지 않더라도, 최소한 수정 사항을 적용하기 위해 부모 컨테이너, 특이성 또는 소스 순서에 얽매이지 않을 것입니다.

물론 다른 옵션은 디자이너에게 버튼이 웹 사이트의 나머지 버튼과 일치해야 한다고 말해 이 문제를 완전히 방지하는 것입니다. 그러나 그것은 다른 날을 위한 것입니다.

5. 수정자, 아니면 새로운 컴포넌트?

가장 큰 문제 중 하나는 컴포넌트가 끝나고 새 컴포넌트가 시작되는 위치를 결정하는 것입니다. 이 c-card의 예에서는 나중에 c-panel라는, 스타일 지정 속성이 매우 유사하지만 몇 가지 눈에 띄는 차이점이 있는 다른 컴포넌트를 만들 수 있습니다 .

그러나 무엇이 이 두 가지를 c-panel과 c-card라는 2가지 컴포넌트를 만들지, 아니면 단순히 c-card의 수정자를 만들지 결정할까요?

과도하게 모듈화하고 모든 것을 컴포넌트로 만들기 쉽습니다. 저는 수정자로 시작하는 것을 추천하지만, 특정 컴포넌트 CSS 파일을 관리하기 어려워진다면 해당 수정자 중 몇 가지를 분리해야 할 때입니다. 새로운 컴포넌트를 만들어야 할 좋은 지표는, 새 수식어의 스타일을 지정하기 위해 모든 "블록" CSS를 재설정해야 하는 자신을 발견했을 때입니다.

가장 좋은 방법은 다른 개발자나 디자이너와 함께 작업하는 경우 그들의 의견을 구하는 것입니다. 몇 분 동안 그들을 잡고 토론하십시오. 나는 이 대답이 약간의 부적절하다는 것을 알고 있지만 대규모 응용 프로그램의 경우 사용 가능한 모듈을 이해하고 컴포넌트를 구성하는 요소에 대해 정확히 동의하는 것이 중요합니다.


너무 길어서 2편으로 나누려고 한다...

반응형

'웹개발 > css' 카테고리의 다른 글

스크롤 해도 고정되는 배너 CSS  (0) 2021.08.25
CSS 깜빡이는 blink 애니메이션 & 바운스 bounce 애니메이션  (0) 2021.07.30
CSS 속성 나열 순서  (0) 2021.07.14
CSS 방법론 BEM  (0) 2021.07.14
CSS 파일 구분  (0) 2021.07.14
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기