홈으로 돌아가기

Vue에서 BEM: 컴포넌트 스타일

이 기사는 Vue에서 BEM을 사용한 구조화된 스타일에 대해 자세히 설명합니다. 수정자가 있는 버튼 예제, scoped 및 스케일링 규칙의 장점. 중급/시니어 개발자에게 적합합니다.

BEM + Vue: 안정적인 스타일링 시스템
Advertisement 728x90

Vue에서 BEM: 확장 가능한 컴포넌트 스타일 구조화

BEM은 Vue 프로젝트에서 여전히 빛을 발합니다. 엄격한 클래스 계층 구조 덕분에 컴포넌트 기반 아키텍처에서 스타일 충돌을 방지하죠. Vue는 반응성과 로직을 담당하고, BEM은 블록과 요소를 독립적으로 유지합니다. 이 조합으로 앱이 커져도 CSS 스파게티가 되지 않습니다.

BEM은 세 가지 핵심 원칙으로 구성됩니다:

  • Block: .header.card처럼 독립적인 단위로, 외부 의존성이 없습니다.
  • Element: 블록의 하위 부분으로 이중 언더스코어로 표시 — .button__icon.
  • Modifier: 단일 언더스코어로 변형이나 상태를 나타냄 — .button_disabled, .card_theme_dark.

이 구조는 스타일을 격리시켜 디버깅과 리팩토링을 수월하게 만듭니다.

Google AdInline article slot

Vue 컴포넌트 스타일링

Vue에서는 <style scoped> 안에 스타일을 넣어 컴포넌트 범위로 제한합니다. Scoped는 스타일 누출을 막지만, 깊은 중첩에는 주의하세요.

외부 라이브러리 통합 시에만 :deep()를 사용하세요. 자체 아키텍처를 해킹하는 데 쓰면 구조적 문제의 신호입니다.

BEM은 scoped와 완벽히 어울리며, 클래스를 논리적으로 그룹화합니다. 블록은 기본 스타일을, 수정자는 변형을, 요소는 내부 구조를 담당하죠.

Google AdInline article slot

실전 예제: 상태가 있는 버튼

시스템 없이 하면 클래스가 무질서하게 늘어납니다. 전형적인 함정:

<template>
  <button :class="{
    'button-basic': isBasic,
    'button-href': isHref,
    'button-avatar': isAvatar 
  }">
    {{ text }}
  </button>
</template>

문제점:

  • 계층 없음: 클래스가 블록과 연결되지 않음.
  • 확장성: 새 상태마다 조건 추가.
  • 가독성: 로직이 시간이 지나 혼란스러워짐.

BEM을 적용하면 템플릿이 간단해지고 자체 문서화됩니다:

Google AdInline article slot
<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

Advertisement 728x90

다음 읽기