Vue에서 BEM: 확장 가능한 컴포넌트 스타일 구조화
BEM은 Vue 프로젝트에서 여전히 빛을 발합니다. 엄격한 클래스 계층 구조 덕분에 컴포넌트 기반 아키텍처에서 스타일 충돌을 방지하죠. Vue는 반응성과 로직을 담당하고, BEM은 블록과 요소를 독립적으로 유지합니다. 이 조합으로 앱이 커져도 CSS 스파게티가 되지 않습니다.
BEM은 세 가지 핵심 원칙으로 구성됩니다:
- Block:
.header나.card처럼 독립적인 단위로, 외부 의존성이 없습니다. - Element: 블록의 하위 부분으로 이중 언더스코어로 표시 —
.button__icon. - Modifier: 단일 언더스코어로 변형이나 상태를 나타냄 —
.button_disabled,.card_theme_dark.
이 구조는 스타일을 격리시켜 디버깅과 리팩토링을 수월하게 만듭니다.
Vue 컴포넌트 스타일링
Vue에서는 <style scoped> 안에 스타일을 넣어 컴포넌트 범위로 제한합니다. Scoped는 스타일 누출을 막지만, 깊은 중첩에는 주의하세요.
외부 라이브러리 통합 시에만 :deep()를 사용하세요. 자체 아키텍처를 해킹하는 데 쓰면 구조적 문제의 신호입니다.
BEM은 scoped와 완벽히 어울리며, 클래스를 논리적으로 그룹화합니다. 블록은 기본 스타일을, 수정자는 변형을, 요소는 내부 구조를 담당하죠.
실전 예제: 상태가 있는 버튼
시스템 없이 하면 클래스가 무질서하게 늘어납니다. 전형적인 함정:
<template>
<button :class="{
'button-basic': isBasic,
'button-href': isHref,
'button-avatar': isAvatar
}">
{{ text }}
</button>
</template>
문제점:
- 계층 없음: 클래스가 블록과 연결되지 않음.
- 확장성: 새 상태마다 조건 추가.
- 가독성: 로직이 시간이 지나 혼란스러워짐.
BEM을 적용하면 템플릿이 간단해지고 자체 문서화됩니다:
<template>
<button :class="[
'button',
{
'button_disabled': disabled,
'button_loading': loading,
},
{
'button_size_xl': size === 'xl',
'button_size_l': size === 'l',
},
{
'button_primary': color === 'primary',
'button_secondary': color === 'secondary',
}
]">
{{ text }}
</button>
</template>
클래스는 의미별로 그룹화: 기본 블록, 상태, 크기, 테마. CSS는:
.button {
/* 기본 스타일 */
padding: 12px 24px;
border: none;
border-radius: 4px;
}
.button_disabled {
opacity: 0.5;
cursor: not-allowed;
}
.button_loading {
position: relative;
}
.button_primary:not(.button_disabled):hover {
background-color: #0055ff;
}
:not() 선택자로 충돌 상태를 필터링해 추가 클래스를 피합니다.
확장성과 팀 협업
대형 프로젝트에서 BEM은 인지 부하를 줄입니다: 개발자가 템플릿에서 블록과 수정자를 바로 확인할 수 있죠. CSS를 뒤지지 않아도 스타일을 이해합니다.
팀 이점:
- 예측 가능성: 클래스 이름이 목적을 반영.
- 격리: 블록 간 간섭 없음.
- 확장성: 리팩토링 없이 새 수정자 추가.
복잡한 컴포넌트 예제 — 테마와 크기가 있는 상품 카드:
<template>
<div class="card" :class="[
`card_size_${size}`,
`card_theme_${theme}`
]">
<div class="card__image"></div>
<div class="card__title">{{ title }}</div>
<button class="card__button button">구매</button>
</div>
</template>
블록 안 요소는 맥락을 상속하지만 독립성을 유지합니다.
BEM을 건너뛸 때
프로토타입이나 랜딩 페이지에는 BEM이 과도합니다: Tailwind나 유틸리티 클래스가 더 빠르죠. 팀과 복잡한 UI의 장기 프로젝트에 BEM을 고수하세요.
핵심 요약
- BEM은 엄격한 계층으로 Vue를 보완하며, scoped 스타일과 충돌 없음.
- 수정자는 상태와 변형을 그룹화해 템플릿 단순화.
:deep()는 외부 라이브러리 전용, 내부 해킹 금지.- 대형 프로젝트에서 BEM은 온보딩과 리팩토링을 가속화.
- 실제 컴포넌트에 적용해 보세요: 가독성이 즉시 향상됩니다.
— Editorial Team
아직 댓글이 없습니다.