posts

화면 로컬 스타일 네이밍 컨벤션 v2.4

Oct 1, 2025 updated Oct 1, 2025 react-nativeux

목차

  1. 목표와 철학
  2. 규칙 TL;DR (바로 쓰는 요약)
  3. 문법(Syntax) — 스코프/슬러그/블록/엘리먼트/모디파이어
  4. 세그먼트 표기법 — camelCase 원칙
  5. 어휘 세트 — Block / Element / Modifier
  6. Modifier 정책 — “기본 1, 최대 2”와 적용 기준
  7. 예시 — Before/After, 실전 패턴
  8. 정규식/린팅 — 자동검증 규칙
  9. 리뷰 체크리스트 — PR용
  10. 마이그레이션 가이드 — 기존 이름 치환 원칙
  11. FAQ — 왜 slug가 선택? 왜 모디파이어를 묶어 쓰나?

1) 목표와 철학

  • 단순·일관: 누구나 바로 이해·검색 가능해야 합니다.
  • 의도 중심: container/wrapper 같은 모호어 금지, “왜 묶였는지”를 드러내는 이름만.
  • BEM 간결 차용: Block/Element/Modifier 개념은 살리되, 언더바만으로 구현.

2) 규칙 TL;DR

  • 형식 styles.<scope>_<slug?>_<block>[_<element>] [__<modifier>[_<modifier>]]

  • 스코프(scope)

    • scr = 화면 로컬
    • w = 위젯 로컬
    • ui = 전역 UI 컴포넌트 (혼동 위험 때문에 u 금지)
  • 세그먼트 내부 표기: camelCase (예: headerRow, footerRow, focusRing)

  • 모디파이어 수: 기본 1개, 최대 2개(서로 다른 축일 때만)


3) 문법(Syntax)

styles.<scope>_<slug?>_<block>
       [ _<element> ]
       [ __<modifier>[_<modifier>] ]
  • <scope>: scr | w | ui (필수)
  • <slug>: 2–4자 화면/도메인 축약(선택, 화면 로컬에서만 권장)
  • <block>: 역할(필수, camelCase)
  • <element>: 블록 내부 단위(선택, 0~1개 권장, camelCase)
  • __<modifier>: 변형/상태(선택, 1개 기본/최대 2개, camelCase)

모디파이어는 항상 한 번의 __로 블록을 열고, 그 안에서 _로 이어붙입니다. 예) __dense / __dense_android __를 여러 번 반복하지 않습니다.


4) 세그먼트 표기법 — camelCase

  • 세그먼트 내부(블록/엘리먼트/모디파이어)는 camelCase. 예) nav, headerRow, footerRow, metaRow, focusRing, gapSm
  • 숫자·치수 금지: _gap10 같은 이름 금지. 값은 토큰(t.spacing.sm)으로.

5) 어휘 세트

Block (필수, 1개 / “역할”)

  • 내비/행동/입력: nav, actions, form, toolbar
  • 콘텐츠/미디어: content, media
  • 목록·표: list, grid, table
  • 탐색보조: tabs, breadcrumbs, filters, sort, pagination
  • 상태/피드백: status, feedback, loading, empty
  • 오버레이/도구: dialog, sheet, menu, popover, tooltip
  • 시각화: carousel, map, chart

container/wrapper 사용 금지. 왜 묶였는지(역할)를 써야 합니다.

Element (선택, 0~1개 권장 / “구조·위치”)

  • 배치/구조: row, column, stack, cluster
  • 스크롤 컨테이너: strip(가로 contentContainerStyle), content(세로)
  • 위치/라인: headerRow, footerRow, lead, trail, aside, main
  • 항목: item, metaRow

Modifier (선택, 기본 1 · 최대 2)

  • 밀도/여백: dense, compact, spacious, padded, gapSm/md/lg
  • 시각: muted, elevated, outlined, seamless
  • 동작: sticky, scrollable, collapsible
  • 플랫폼/방향: ios, android, web, rtl

조합 원칙: 서로 다른 축만 조합. 예) dense + android(밀도+플랫폼) ✅ / dense + compact(둘 다 밀도) ❌


6) Modifier 정책 — “기본 1, 최대 2” 왜?

  • 기본 1개: 이름 길이/복잡성·검색성을 모두 고려한 기본값.

  • 최대 2개 허용: 아주 드물게, 서로 다른 축이 동시에 필요할 때만.

    • 예) __dense_android, __sticky_rtl
  • 금지 케이스

    • 같은 축 반복: __dense_compact (둘 다 밀도)
    • 3개 이상: __dense_muted_sticky → 개별 스타일 분리/조합으로 해결
  • 우선순위(표기 순서 권장): density/spacing → visual → behavior → platform/dir

    • 예) __compact_sticky_android

7) 예시

7.1 기존 코드 리팩터링

// Before
scr_forums_section_nav_short
scr_forums_section_nav
scr_forums_group_nav_strip

// After (slug=frm)
styles.scr_frm_nav__compact            // “short”의 의도를 compact로
styles.scr_frm_nav                     // 기본 네비 묶음
styles.scr_frm_nav_strip__dense        // 가로 스크롤(contentContainerStyle)

7.2 헤더/CTA/푸터

styles.w_header_actions_row                    // 위젯 로컬
styles.scr_frm_actions_headerRow               // 화면 로컬 헤더 액션 줄
styles.scr_frm_actions_footerRow__sticky_ios   // 하단 고정 CTA(iOS)

7.3 검색/필터

styles.scr_srch_filters_strip__dense
styles.scr_srch_form_column__padded

7.4 두 개 모디파이어(서로 다른 축 조합)

styles.scr_frm_nav_strip__dense_android        // 밀도 + 플랫폼
styles.scr_frm_actions_footerRow__sticky_rtl   // 동작 + 방향

8) 정규식/린팅

허용 패턴(슬러그 선택/모디파이어 0~2개 한정):

^(scr|w|ui)_[a-z0-9]{0,4}_[a-z][a-zA-Z0-9]*           # <scope>_<slug?>_<block>
(?:_[a-z][a-zA-Z0-9]*)?                               # _<element> (optional)
(?:__[a-z][a-zA-Z0-9]*(?:_[a-z][a-zA-Z0-9]*){0,1})?$  # __<modifier>[_<modifier>] (0~2)
  • 예: scr_frm_nav_strip__dense, scr_srch_form_column__padded, w_header_actions_row, ui_button_root

금지 룰(별도 검사):

  • container|wrapper 포함
  • _gap[0-9]+숫자 변형
  • 접두사 u_ (→ ui_만 허용)

9) 리뷰 체크리스트 (PR용)

  • scr|w|ui 스코프 적절히 사용?
  • (scr일 때) 슬러그 필요하면 2–4자로 붙였는가?
  • Block이 역할을 명확히 드러내는가? (container/wrapper 금지)
  • Element는 필요한 경우에만 1개 이내 사용했는가?
  • Modifier는 __ 블록에, 1개 기본/2개 이내인가?
  • 세그먼트 내부는 camelCase인가?
  • 숫자/매직넘버는 이름에 없고 값은 토큰으로?
  • strip은 가로 contentContainerStyle 전용으로 썼는가?

10) 마이그레이션 가이드

  1. *_container/*_wrapper → 역할형 Block으로: nav, actions, content
  2. *_item(컨테이너 의미로 오용) → strip(가로) / content(세로)
  3. short/long__compact / __spacious
  4. 숫자 접미 → __gapSm/md/lg + 실제 값은 t.spacing.*
  5. 기존 다중 수식 → 최대 2개만 남기고 나머지는 스타일 분리

11) FAQ

Q. 모디파이어는 왜 여러 개가 필요한가요? A. 대부분 1개면 충분합니다. 다만 서로 다른 축이 동시에 요구될 때(예: “compact” + “android”)가 드물게 존재합니다. 이때만 2개를 허용합니다. 그 이상은 유지보수 비용만 커집니다.

Q. slug는 항상 붙여야 하나요? A. 화면이 적고 충돌 우려가 없으면 생략 가능. 다만 장기적으로는 scr_<slug>_…가 전역 검색·리팩터에 유리합니다(권장).

Q. 왜 camelCase인가요? A. 언더바는 세그먼트 경계·모디파이어 연결 전용으로 두고, 내부 단어는 camelCase로 읽기 좋게 유지하기 위함입니다.