SwiftUI 디자인 토큰 및 테마 시스템 (프로덕션 규모)
Source: Dev.to
SwiftUI 앱이 커짐에 따라 UI 일관성이 깨지기 쉽습니다. 다음과 같은 문제가 나타납니다:
- 약간씩 다른 패딩 값
- 일관되지 않은 코너 반경
- 곳곳에 하드코딩된 무작위 색상
- 다크 모드 버그
- 접근성 문제
- 번거로운 리브랜딩 작업
해결책은 디자인 토큰 — 모든 시각적 결정을 위한 단일 진실 소스입니다. 이 포스트에서는 SwiftUI에서 프로덕션 수준의 디자인 토큰 및 테마 시스템을 깔끔하게 확장하는 방법을 보여줍니다.
🧠 디자인 토큰이란?
디자인 토큰은 이름이 붙은 의미론적 값이며, 원시 숫자가 아닙니다.
잘못된 예
.padding(12)
.cornerRadius(16)
.foregroundColor(.blue)
올바른 예
.padding(.md)
.cornerRadius(.card)
.foregroundStyle(.accent)
토큰은 구현이 아니라 의도를 표현합니다.
📦 1. 핵심 토큰 카테고리
완전한 시스템은 보통 다음을 포함합니다:
- Spacing (간격)
- Radius (반경)
- Typography (타이포그래피)
- Colors (색상)
- Elevation (입체감)
- Animation (애니메이션)
- Opacity (불투명도)
각 항목을 깔끔하게 정의합니다.
📏 2. Spacing 토큰
enum Spacing {
static let xs: CGFloat = 4
static let sm: CGFloat = 8
static let md: CGFloat = 16
static let lg: CGFloat = 24
static let xl: CGFloat = 32
}
사용 예
.padding(Spacing.md)
🔲 3. Corner Radius 토큰
enum Radius {
static let sm: CGFloat = 6
static let md: CGFloat = 12
static let lg: CGFloat = 20
static let card: CGFloat = 16
}
🎨 4. Color 토큰 (시맨틱, 비주얼이 아님)
절대 이렇게 하지 마세요:
Color.blue
대신 이렇게 사용합니다:
enum AppColor {
static let background = Color("Background")
static let surface = Color("Surface")
static let accent = Color("Accent")
static let textPrimary = Color("TextPrimary")
static let textSecondary = Color("TextSecondary")
}
Assets가 라이트/다크 모드, 접근성 대비, 브랜드 변경을 처리합니다.
🔤 5. Typography 토큰
enum AppFont {
static let title = Font.system(size: 28, weight: .bold)
static let headline = Font.system(size: 20, weight: .semibold)
static let body = Font.system(size: 16)
static let caption = Font.system(size: 13)
}
사용 예
Text("Title")
.font(AppFont.title)
🧊 6. Elevation & Material 토큰
enum Elevation {
static let card = CGFloat(4)
static let modal = CGFloat(12)
}
.background(.ultraThinMaterial)
.shadow(radius: Elevation.card)
🕺 7. Animation 토큰
enum Motion {
static let fast = Animation.easeOut(duration: 0.15)
static let standard = Animation.easeInOut(duration: 0.25)
static let slow = Animation.spring(response: 0.45)
}
🌗 8. Theme Container
테마 모델을 생성합니다:
struct AppTheme {
let colors: AppColor.Type
let spacing: Spacing.Type
let radius: Radius.Type
}
환경을 통해 주입합니다:
.environment(\.theme, currentTheme)
🔁 9. 다중 테마 지원
enum ThemeKind {
case light
case dark
case highContrast
}
다음에 따라 동적으로 전환합니다:
- 시스템 외관
- 접근성 설정
- 사용자 선호도
- A/B 테스트
🧪 10. 프리뷰가 강력해짐
#Preview("Dark") {
ContentView()
.environment(\.theme, .dark)
}
디자인 검증이 즉시 이루어집니다.
🚀 최종 생각
디자인 토큰 시스템을 도입하면 다음과 같은 이점을 얻습니다:
- 일관성
- 접근성
- 빠른 반복
- 안전한 리팩터링
- 쉬운 리브랜딩
- 깔끔한 코드
- 더 행복한 디자이너
한 번 토큰을 사용하면 다시는 돌아가지 못합니다.