Quasar의 prop이 SCSS와 매핑되는 원리 — BEM, DOM 클래스, 그리고 UI 프레임워크의 공통 패턴
이 글에서 다루는 내용
Quasar에서 flat이라는 prop을 쓰면 SCSS 셀렉터 .q-btn--flat이 매칭되는 이유가 궁금했다. prop은 Vue의 영역이고 SCSS는 CSS의 영역인데, 둘이 어떻게 연결되는 걸까? 이 글에서는 그 연결 고리를 BEM 방법론과 함께 정리한다.
발단 — 이 SCSS 코드에서 시작됐다
.app-btn.q-btn,
.app-ghost-btn.q-btn.q-btn--flat {
&.h-92 {
height: 92px;
font-size: 30px;
}
}
여기서 .q-btn--flat이라는 셀렉터가 눈에 띄었다. flat은 Quasar의 prop인데, 왜 SCSS에서 클래스처럼 사용되는 걸까?
prop이 클래스로 변환된다
핵심은 Quasar가 flat prop을 받으면 내부 JS 로직이 DOM에 클래스를 자동으로 추가한다는 것이다.
<!-- 개발자가 작성한 코드 -->
<q-btn class="app-ghost-btn" flat />
<!-- 실제 렌더링된 DOM -->
<button class="app-ghost-btn q-btn q-btn--flat ...">
흐름을 정리하면:
flat prop (Vue)
→ Quasar 내부 JS가 감지
→ q-btn--flat 클래스를 DOM에 추가
→ SCSS 셀렉터가 매칭
즉, SCSS가 flat prop 자체를 선택하는 게 아니라, Quasar가 그 prop을 보고 붙여준 클래스를 선택하는 것이다.
BEM 방법론과의 관계
q-btn--flat에서 --는 BEM 방법론의 Modifier를 의미한다.
q-btn ← Block
q-btn--flat ← Block + Modifier (상태/변형)
q-btn__label ← Block + Element
--: 변형/상태 (flat, round, disabled 등)__: 구성 요소 (label, icon, wrapper 등)
Quasar가 BEM 네이밍을 따르기 때문에 prop 값에 따라 q-btn--flat, q-btn--round, q-btn--disabled 같은 클래스를 자동으로 붙여주는 것이다.
__와 --의 차이
__ Element |
-- Modifier |
|
|---|---|---|
| 생성 시점 | 렌더링 시 항상 고정 | prop/상태에 따라 동적 |
| 용도 | 내부 구조 표현 | 변형/상태 표현 |
| 예 | q-btn__label |
q-btn--flat |
__는 prop 없이 컴포넌트 내부 HTML 구조 자체가 항상 그 클래스를 가진다. 반면 --는 prop 값에 따라 조건부로 붙는다.
<!-- q-btn 렌더링 결과 -->
<button class="q-btn">
<span class="q-btn__wrapper"> <!-- 항상 존재 -->
<span class="q-btn__content"> <!-- 항상 존재 -->
<span class="q-btn__label"> <!-- 항상 존재 -->
Click
</span>
</span>
</span>
</button>
클래스를 직접 써도 될까?
<q-btn class="q-btn--flat" />
스타일은 적용되지만 Quasar 내부 동작(접근성, 기타 로직)은 작동하지 않을 수 있다. prop을 통해 쓰는 것이 올바른 방법이다.
이건 Quasar만의 패턴이 아니다
대부분의 UI 프레임워크가 동일한 방식으로 동작한다.
<!-- Vuetify -->
<v-btn outlined /> → v-btn--outlined
<!-- MUI (React) -->
<Button variant="outlined" /> → MuiButton-outlined
<!-- Angular Material -->
<mat-button color="primary" /> → mat-button-primary
네이티브도 마찬가지다.
// iOS SwiftUI
Button("Click").buttonStyle(.bordered)
// Android Jetpack Compose
Button(colors = ButtonDefaults.outlinedButtonColors())
공통 철학:
개발자는 "어떻게 보일지"를 prop/속성으로 선언
↓
프레임워크가 내부적으로 스타일(클래스)로 변환
정리
| 개념 | 설명 |
|---|---|
flat prop |
Vue/Quasar의 영역. 의미 있는 값으로 선언 |
q-btn--flat |
BEM Modifier 클래스. DOM에 동적으로 추가됨 |
| SCSS 셀렉터 | DOM에 추가된 클래스를 선택 |
BEM __ |
내부 구조, 항상 고정 |
BEM -- |
상태/변형, 조건부 |
눈에 보이는 코드(Vue prop, SCSS)가 분리되어 있고 그 사이를 프레임워크 JS가 연결하기 때문에 처음엔 암묵적으로 느껴질 수 있다. 브라우저 DevTools에서 실제 DOM 클래스를 확인하면서 연결 고리를 직접 눈으로 보는 것이 가장 빠른 이해 방법이다.