Block__Element--Modifier
↑ ↑ ↑
블록 엘리먼트 수정자.card { } /* 카드 블록 */
.nav { } /* 내비게이션 블록 */
.button { } /* 버튼 블록 */.card__title { } /* 카드 안의 제목 */
.card__image { } /* 카드 안의 이미지 */
.card__footer { } /* 카드 안의 푸터 */
.nav__item { } /* 내비게이션의 항목 */
.nav__link { } /* 내비게이션 항목 안의 링크 */<!-- 이렇게 하면 안 된다 -->
<div class="card">
<div class="card__footer">
<button class="card__footer__button">확인</button> ← 중첩 금지
</div>
</div>
<!-- BEM에서 맞는 방식 -->
<div class="card">
<div class="card__footer">
<button class="card__button">확인</button> ← Block 기준으로 평탄화
</div>
</div>.button--primary { } /* 주요 액션 버튼 */
.button--disabled { } /* 비활성화된 버튼 */
.button--large { } /* 큰 버튼 */
.card--highlighted { } /* 강조된 카드 */
.nav__item--active { } /* 활성화된 내비게이션 항목 */<!-- 맞는 방식 -->
<button class="button button--primary">저장</button>
<!-- 틀린 방식 — Modifier만 단독 사용 -->
<button class="button--primary">저장</button>인라인 스타일 > ID > 클래스 > 태그
specificity: (0, 0, 0, 0)
↑ ↑ ↑ ↑
인라인 ID 클래스 태그/* BEM 방식 — 특이도: (0,0,1,0) */
.card__title { color: black; }
/* 비BEM 방식 — 특이도: (0,0,1,1) */
.card h2 { color: black; }
/* 비BEM 방식 — 특이도: (0,1,0,0) */
#card-title { color: black; }.button {
background: gray;
color: white;
padding: 8px 16px;
}
.button--primary {
background: blue; /* 같은 특이도, 뒤에 선언돼서 덮어씀 */
}
.button--large {
padding: 12px 24px; /* 같은 특이도, 정상적으로 덮어씀 */
}<article class="card card--featured"> <!-- ← Block + Modifier -->
<img class="card__image" src="..." /> <!-- ← Element -->
<div class="card__body"> <!-- ← Element -->
<h2 class="card__title">제목</h2> <!-- ← Element -->
<p class="card__description">설명</p> <!-- ← Element -->
</div>
<footer class="card__footer"> <!-- ← Element -->
<button class="button button--primary"> <!-- ← 별도 Block + Modifier -->
자세히 보기
</button>
</footer>
</article>
// 계속 `prefix` 가 붙는 구조
<div class="card">
<h2 class="card__title">제목</h2> <!-- card__ 계속 반복 -->
<img class="card__image" /> <!-- card__ 계속 반복 -->
<p class="card__description">설명</p> <!-- card__ 계속 반복 -->
</div>// 구조적인 SCSS 중첩 구조
.card {
background: white;
&__title { // ← 컴파일하면 .card__title
font-size: 20px;
}
&__image { // ← .card__image
width: 100%;
}
&--featured { // ← .card--featured (Modifier)
border: 2px solid blue;
}
&--featured &__title { // ← .card--featured .card__title
color: blue;
}
}방법론 | 핵심 아이디어 | 네이밍 예시 | 특이도 관리 | 학습 곡선 |
BEM | Block–Element–Modifier 구조화 | .card__title--bold | 균일하게 낮음 | 중간 |
OOCSS | 구조와 스킨 분리 | .btn .btn-skin-blue | 보통 | 낮음 |
SMACSS | 카테고리별 분류 (Base, Layout, Module...) | .l-grid, .is-active | 카테고리마다 다름 | 높음 |
CSS Modules | 로컬 스코프로 충돌 방지 | styles.card (컴파일 후 해시) | 자동 격리 | 낮음 |
Utility-first (Tailwind) | 작은 유틸리티 클래스 조합 | flex gap-4 p-4 rounded | 거의 없음 | 낮음 |
/* 라이브러리 수준에서 명확한 네임스페이스 */
.ds-button { } /* ds = design system */
.ds-button--primary { }
.ds-card__title { }<!-- nav__item이면서 동시에 독립적인 link Block -->
<a class="link nav__item" href="...">메뉴</a>/* Boolean Modifier */
.button--disabled { }
/* Key-Value Modifier */
.button--size-large { } /* size: large */
.button--theme-dark { } /* theme: dark */.c-card { } /* c = component */
.l-header { } /* l = layout */
.u-visually-hidden { } /* u = utility */
.js-modal-trigger { } /* js = JavaScript hook, 스타일 없음 */