mirror of
https://github.com/cna-bootcamp/phonebill.git
synced 2025-12-05 23:56:23 +00:00
16 KiB
16 KiB
통신요금 관리 서비스 - 스타일 가이드
브랜드 아이덴티티
서비스 컨셉
- 키워드: 신뢰성, 편리함, 명확성
- 브랜드 메시지: "간편하고 안전한 통신요금 관리"
- 타겟: 일반 MVNO 고객 (20대~60대)
디자인 컨셉
- 미니멀리즘: 불필요한 요소 제거, 핵심 기능 집중
- 명확성 우선: 정보 전달의 명확성과 가독성
- 안정감: 금융 서비스의 신뢰성과 보안성 강조
- 접근성: 모든 사용자가 편리하게 이용할 수 있는 인터페이스
디자인 원칙
1. 명확성 (Clarity)
- 모든 UI 요소는 그 목적이 명확해야 함
- 전문용어 사용 최소화, 일반적인 표현 우선
- 중요 정보는 시각적으로 강조
2. 일관성 (Consistency)
- 동일한 요소는 동일한 스타일 적용
- 예측 가능한 인터랙션 패턴
- 통일된 색상과 타이포그래피 사용
3. 효율성 (Efficiency)
- 최소한의 클릭으로 목표 달성
- 불필요한 단계 제거
- 빠른 로딩과 반응성 보장
4. 안전성 (Safety)
- 중요한 액션에는 확인 단계 제공
- 오류 방지와 명확한 피드백
- 개인정보 보호 강조
5. 포용성 (Inclusivity)
- 접근성 지침 준수
- 다양한 디바이스와 환경 지원
- 사용자 능력과 상황 고려
컬러 시스템
Primary Colors
/* 메인 브랜드 컬러 - 신뢰감을 주는 블루 */
--primary-50: #EBF8FF;
--primary-100: #BEE3F8;
--primary-200: #90CDF4;
--primary-300: #63B3ED;
--primary-400: #4299E1;
--primary-500: #3182CE; /* Main Brand Color */
--primary-600: #2B77CB;
--primary-700: #2C5282;
--primary-800: #2A4365;
--primary-900: #1A365D;
Secondary Colors
/* 보조 컬러 - 포인트 및 상태 표시 */
--secondary-50: #F7FAFC;
--secondary-100: #EDF2F7;
--secondary-200: #E2E8F0;
--secondary-300: #CBD5E0;
--secondary-400: #A0AEC0;
--secondary-500: #718096;
--secondary-600: #4A5568;
--secondary-700: #2D3748;
--secondary-800: #1A202C;
--secondary-900: #171923;
Status Colors
/* 성공 - 그린 */
--success-50: #F0FFF4;
--success-100: #C6F6D5;
--success-500: #38A169;
--success-600: #2F855A;
/* 경고 - 오렌지 */
--warning-50: #FFFAF0;
--warning-100: #FEEBC8;
--warning-500: #ED8936;
--warning-600: #DD6B20;
/* 오류 - 레드 */
--error-50: #FED7D7;
--error-100: #FED7D7;
--error-500: #E53E3E;
--error-600: #C53030;
/* 정보 - 블루 */
--info-50: #EBF8FF;
--info-100: #BEE3F8;
--info-500: #3182CE;
--info-600: #2B77CB;
Neutral Colors
/* 텍스트 및 배경 */
--gray-50: #F9FAFB; /* Background Light */
--gray-100: #F3F4F6; /* Background */
--gray-200: #E5E7EB; /* Border Light */
--gray-300: #D1D5DB; /* Border */
--gray-400: #9CA3AF; /* Text Muted */
--gray-500: #6B7280; /* Text Secondary */
--gray-600: #4B5563; /* Text Primary Light */
--gray-700: #374151; /* Text Primary */
--gray-800: #1F2937; /* Text Primary Dark */
--gray-900: #111827; /* Text Emphasis */
컬러 사용 가이드
- Primary: 주요 액션 버튼, 링크, 브랜드 요소
- Secondary: 보조 버튼, 아이콘, 경계선
- Success: 성공 메시지, 완료 상태
- Warning: 주의 메시지, 중요 알림
- Error: 오류 메시지, 실패 상태
- Gray: 텍스트, 배경, 구분선
타이포그래피
폰트 패밀리
/* 기본 폰트 스택 */
font-family:
'Noto Sans KR', /* 한글 */
'Roboto', /* 영문 */
-apple-system,
BlinkMacSystemFont,
'Apple SD Gothic Neo',
'Malgun Gothic',
sans-serif;
폰트 크기 및 행간
/* Heading */
--text-4xl: 2.25rem; /* 36px - Page Title */
--text-3xl: 1.875rem; /* 30px - Section Title */
--text-2xl: 1.5rem; /* 24px - Card Title */
--text-xl: 1.25rem; /* 20px - Sub Title */
--text-lg: 1.125rem; /* 18px - Large Text */
/* Body */
--text-base: 1rem; /* 16px - Body Text */
--text-sm: 0.875rem; /* 14px - Small Text */
--text-xs: 0.75rem; /* 12px - Caption */
/* Line Height */
--leading-tight: 1.25; /* Heading */
--leading-normal: 1.5; /* Body */
--leading-relaxed: 1.625; /* Long Text */
폰트 두께
--font-light: 300; /* Light text */
--font-normal: 400; /* Body text */
--font-medium: 500; /* Emphasis */
--font-semibold: 600; /* Sub heading */
--font-bold: 700; /* Heading */
타이포그래피 클래스
/* Heading Styles */
.heading-1 { font-size: 2.25rem; font-weight: 700; line-height: 1.25; }
.heading-2 { font-size: 1.875rem; font-weight: 600; line-height: 1.25; }
.heading-3 { font-size: 1.5rem; font-weight: 600; line-height: 1.25; }
.heading-4 { font-size: 1.25rem; font-weight: 500; line-height: 1.25; }
/* Body Styles */
.body-large { font-size: 1.125rem; font-weight: 400; line-height: 1.5; }
.body-normal { font-size: 1rem; font-weight: 400; line-height: 1.5; }
.body-small { font-size: 0.875rem; font-weight: 400; line-height: 1.5; }
.caption { font-size: 0.75rem; font-weight: 400; line-height: 1.25; }
/* Emphasis */
.text-emphasis { font-weight: 600; color: var(--gray-900); }
.text-muted { color: var(--gray-500); }
간격 시스템
기본 간격 단위 (8px 그리드 시스템)
--space-0: 0;
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
--space-20: 5rem; /* 80px */
컴포넌트별 간격 가이드
- Component Padding: 16px (space-4) - 24px (space-6)
- Content Margin: 16px (space-4) - 32px (space-8)
- Section Gap: 32px (space-8) - 48px (space-12)
- Page Padding: 20px (space-5) - 40px (space-10)
레이아웃 간격
/* Container */
--container-padding-mobile: var(--space-4); /* 16px */
--container-padding-tablet: var(--space-6); /* 24px */
--container-padding-desktop: var(--space-8); /* 32px */
/* Grid Gap */
--grid-gap-small: var(--space-4); /* 16px */
--grid-gap-medium: var(--space-6); /* 24px */
--grid-gap-large: var(--space-8); /* 32px */
컴포넌트 스타일
버튼 (Button)
/* Base Button */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--space-3) var(--space-6);
border-radius: 8px;
font-size: var(--text-base);
font-weight: var(--font-medium);
line-height: 1.5;
transition: all 0.2s ease-in-out;
cursor: pointer;
border: none;
min-height: 44px; /* 터치 접근성 */
}
/* Primary Button */
.btn-primary {
background-color: var(--primary-500);
color: white;
}
.btn-primary:hover {
background-color: var(--primary-600);
}
.btn-primary:disabled {
background-color: var(--gray-300);
color: var(--gray-500);
cursor: not-allowed;
}
/* Secondary Button */
.btn-secondary {
background-color: white;
color: var(--gray-700);
border: 1px solid var(--gray-300);
}
.btn-secondary:hover {
background-color: var(--gray-50);
border-color: var(--gray-400);
}
/* Danger Button */
.btn-danger {
background-color: var(--error-500);
color: white;
}
.btn-danger:hover {
background-color: var(--error-600);
}
카드 (Card)
.card {
background-color: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
padding: var(--space-6);
border: 1px solid var(--gray-200);
}
.card-header {
margin-bottom: var(--space-4);
padding-bottom: var(--space-4);
border-bottom: 1px solid var(--gray-200);
}
.card-title {
font-size: var(--text-xl);
font-weight: var(--font-semibold);
color: var(--gray-900);
margin: 0;
}
.card-content {
color: var(--gray-700);
}
폼 요소 (Form)
/* Input */
.input {
width: 100%;
padding: var(--space-3) var(--space-4);
border: 1px solid var(--gray-300);
border-radius: 8px;
font-size: var(--text-base);
line-height: 1.5;
transition: border-color 0.2s ease-in-out;
min-height: 44px;
}
.input:focus {
outline: none;
border-color: var(--primary-500);
box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.1);
}
.input.error {
border-color: var(--error-500);
}
/* Label */
.label {
display: block;
font-size: var(--text-sm);
font-weight: var(--font-medium);
color: var(--gray-700);
margin-bottom: var(--space-2);
}
/* Select */
.select {
appearance: none;
background-image: url("data:image/svg+xml,..."); /* 드롭다운 아이콘 */
background-repeat: no-repeat;
background-position: right var(--space-3) center;
background-size: 16px;
}
알림 메시지 (Alert)
.alert {
padding: var(--space-4);
border-radius: 8px;
border-left: 4px solid;
margin-bottom: var(--space-4);
}
.alert-success {
background-color: var(--success-50);
border-color: var(--success-500);
color: var(--success-800);
}
.alert-warning {
background-color: var(--warning-50);
border-color: var(--warning-500);
color: var(--warning-800);
}
.alert-error {
background-color: var(--error-50);
border-color: var(--error-500);
color: var(--error-800);
}
.alert-info {
background-color: var(--info-50);
border-color: var(--info-500);
color: var(--info-800);
}
반응형 브레이크포인트
브레이크포인트 정의
/* Mobile First Approach */
:root {
--breakpoint-sm: 640px; /* Small devices */
--breakpoint-md: 768px; /* Medium devices */
--breakpoint-lg: 1024px; /* Large devices */
--breakpoint-xl: 1280px; /* Extra large devices */
}
/* Media Query Mixins */
@media (min-width: 640px) { /* sm */ }
@media (min-width: 768px) { /* md */ }
@media (min-width: 1024px) { /* lg */ }
@media (min-width: 1280px) { /* xl */ }
반응형 컨테이너
.container {
width: 100%;
margin: 0 auto;
padding: 0 var(--space-4);
}
@media (min-width: 640px) {
.container {
max-width: 640px;
padding: 0 var(--space-6);
}
}
@media (min-width: 768px) {
.container {
max-width: 768px;
}
}
@media (min-width: 1024px) {
.container {
max-width: 1024px;
padding: 0 var(--space-8);
}
}
반응형 그리드
.grid {
display: grid;
gap: var(--space-4);
grid-template-columns: 1fr; /* Mobile: 1 column */
}
@media (min-width: 768px) {
.grid-md-2 {
grid-template-columns: repeat(2, 1fr); /* Tablet: 2 columns */
}
}
@media (min-width: 1024px) {
.grid-lg-3 {
grid-template-columns: repeat(3, 1fr); /* Desktop: 3 columns */
}
}
대상 서비스 특화 컴포넌트
요금 정보 카드 (Bill Card)
.bill-card {
background: linear-gradient(135deg, var(--primary-500) 0%, var(--primary-600) 100%);
color: white;
padding: var(--space-6);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(49, 130, 206, 0.2);
}
.bill-amount {
font-size: var(--text-4xl);
font-weight: var(--font-bold);
margin-bottom: var(--space-2);
}
.bill-period {
font-size: var(--text-sm);
opacity: 0.8;
}
.bill-details {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 8px;
padding: var(--space-4);
margin-top: var(--space-4);
}
상품 비교 카드 (Product Card)
.product-card {
border: 2px solid var(--gray-200);
border-radius: 12px;
padding: var(--space-6);
transition: all 0.3s ease;
position: relative;
}
.product-card.selected {
border-color: var(--primary-500);
box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.1);
}
.product-card.current {
background-color: var(--success-50);
border-color: var(--success-500);
}
.product-badge {
position: absolute;
top: -8px;
right: var(--space-4);
background-color: var(--primary-500);
color: white;
padding: var(--space-1) var(--space-3);
border-radius: 999px;
font-size: var(--text-xs);
font-weight: var(--font-medium);
}
.product-price {
font-size: var(--text-2xl);
font-weight: var(--font-bold);
color: var(--primary-600);
}
진행 상태 표시 (Progress)
.progress-container {
background-color: var(--gray-100);
border-radius: 999px;
height: 8px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, var(--primary-500) 0%, var(--primary-400) 100%);
border-radius: 999px;
transition: width 0.3s ease;
}
.progress-steps {
display: flex;
justify-content: space-between;
margin-bottom: var(--space-4);
}
.progress-step {
display: flex;
align-items: center;
font-size: var(--text-sm);
color: var(--gray-500);
}
.progress-step.active {
color: var(--primary-600);
font-weight: var(--font-medium);
}
.progress-step.completed {
color: var(--success-600);
}
상태 뱃지 (Status Badge)
.status-badge {
display: inline-flex;
align-items: center;
padding: var(--space-1) var(--space-3);
border-radius: 999px;
font-size: var(--text-xs);
font-weight: var(--font-medium);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.status-badge.processing {
background-color: var(--warning-100);
color: var(--warning-800);
}
.status-badge.completed {
background-color: var(--success-100);
color: var(--success-800);
}
.status-badge.failed {
background-color: var(--error-100);
color: var(--error-800);
}
.status-badge::before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
background-color: currentColor;
margin-right: var(--space-2);
}
인터랙션 패턴
애니메이션 타이밍
:root {
--duration-fast: 0.15s;
--duration-normal: 0.3s;
--duration-slow: 0.5s;
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}
호버 효과
.interactive:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transition: all var(--duration-normal) var(--ease-out);
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
로딩 상태
.loading {
position: relative;
pointer-events: none;
opacity: 0.6;
}
.loading::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 20px;
height: 20px;
border: 2px solid var(--gray-300);
border-top: 2px solid var(--primary-500);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
포커스 상태
.focusable:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.3);
border-radius: 8px;
}
.focus-visible {
outline: 2px solid var(--primary-500);
outline-offset: 2px;
}
상태 전환
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity var(--duration-normal) var(--ease-out);
}
.slide-enter {
transform: translateX(100%);
}
.slide-enter-active {
transform: translateX(0);
transition: transform var(--duration-normal) var(--ease-out);
}
변경 이력
| 버전 | 날짜 | 변경사항 | 작성자 |
|---|---|---|---|
| 1.0 | 2025-01-05 | 초기 스타일 가이드 작성 | 박화면 |
스타일 가이드 활용 방법
CSS 변수 사용
모든 스타일 정의에서 CSS 변수를 사용하여 일관성을 유지하고 쉬운 테마 변경을 지원합니다.
컴포넌트 기반 설계
재사용 가능한 컴포넌트 스타일을 정의하여 개발 효율성과 일관성을 높입니다.
접근성 고려
모든 컴포넌트는 WCAG 2.1 AA 기준을 준수하여 접근성을 보장합니다.
반응형 우선
Mobile First 접근 방식으로 모든 디바이스에서 최적의 사용자 경험을 제공합니다.