> For the complete documentation index, see [llms.txt](https://here-we.gitbook.io/here-we/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://here-we.gitbook.io/here-we/frontend/ui.md).

# 디자인 시스템 구축 및 UI 일관성 개선

현대 웹 개발에서는 **디자인 시스템**이 중요한 역할을 합니다. 디자인 시스템을 도입하면 UI의 일관성을 유지하고, 유지보수를 쉽게 하며, 협업을 원활하게 할 수 있습니다. 이번 글에서는 디자인 토큰(Color, Typography, Spacing, Breakpoint)을 활용해 코드에서 디자인 시스템을 구축한 방법에 대해 설명하겠습니다.

### 디자인 시스템이 없을 경우 코드에서 발생하는 문제점

디자인 시스템이 없을 경우, 코드 내에서 다음과 같은 문제점이 발생할 수 있습니다:

1. **중복된 코드 증가**
   * 동일한 스타일이 여러 곳에서 반복적으로 정의되면서 코드가 불필요하게 길어집니다.
   * 예를 들어, 여러 파일에서 `.button { background-color: #0d7bff; }` 같은 코드가 중복될 수 있습니다.
2. **유지보수성 저하**
   * 특정 스타일을 변경해야 할 때, 모든 관련 CSS 파일을 찾아 수정해야 합니다.
   * 예를 들어, 브랜드 색상을 변경하려면 수십 개의 CSS 파일을 일일이 수정해야 할 수도 있습니다.

이러한 문제를 해결하기 위해 **디자인 시스템과 디자인 토큰**을 도입하여 유지보수를 쉽게 할 필요가 있습니다.

### **🎨 디자인 토큰을 활용한 UI 일관성 유지**

디자인 시스템을 구축할 때, 가장 중요한 요소 중 하나는 **디자인 토큰**입니다. 디자인 토큰은 색상, 폰트, 간격, 반응형 브레이크포인트 등의 스타일 정보를 변수화하여 **일관된 디자인을 유지**하고 **유지보수를 쉽게** 만들어 줍니다.

### **색상(Color) 시스템 구축**

색상 시스템을 설계할 때는 **Sass의 맵(map) 데이터 구조**를 활용하여 **색상 토큰을 정의**하고, 이를 기반으로 **라이트/다크 모드**를 쉽게 관리할 수 있도록 만들었습니다.

**📌 색상 변수 정의 (Sass Map 활용)**

Sass에서 `()`를 사용하면 **맵(Map)**&#xC744; 만들 수 있습니다. 맵은 **키(Key)와 값(Value)**&#xC758; 쌍으로 데이터를 저장하는 구조입니다. 위의 코드에서 `colors` 변수를 **중첩된 맵(Nested Map)** 형태로 작성하였습니다.

`colors` 맵에는 `'blue'`와 `'gray'`라는 색상 그룹이 정의되어 있습니다. 각 그룹은 **50부터 900까지의 숫자 키**를 가지며, 각 키에 해당하는 색상 코드를 값으로 저장하였습니다.

```tsx
$colors: (
  'blue': (
    50: #eaf4ff,
    100: #d6e9ff,
    ...
    900: #001a4d,
  ),
  'gray': (
    50: #f8fafc,
    100: #f1f5f9,
    ...
    900: #0f172a,
  ),
);
```

**📌 색상 값을 추출하는 함수 생성**

위의 $color 변수에서 색상을 가져올 때 map.get 함수를 직접 사용해서 색상을 가져오면 아래와 같이 코드를 반복해서 작성해야 하는 불편함이 있었습니다.

```tsx
// 예시 
$brand: map.get(map.get($colors, 'blue'), 500);
$secondary: map.get(map.get($colors, 'gray'), 900);
```

따라서 `@function color()`를 만들어 활용했습니다. 이를 통해 `color('blue', 500)`처럼 간단한 함수 호출만으로 원하는 색상을 추출할 수 있습니다. `$colors` 맵에서 `$color` 그룹을 가져온 후 (예: 'blue') , 해당 색상 그룹에서 $scale 에 해당하는 색상 값을 가져옵니다. (예: 500이면 #368fff)

```tsx
@use 'sass:map'; //Sass의 map 모듈을 사용하여 map.get() 함수를 활용할 수 있도록 함.

@function color($color, $scale) {
  @return map.get(map.get($colors, $color), $scale);
}

// 예시 
$brand: color('blue', 500)
$secondary: color('gray', 100)
```

**css의 변수가 아니라 Sass의 맵(Map) 구조를 활용한 이유**

`--primary-color`와 같은 단순 CSS 변수만으로는 스타일을 체계적으로 그룹화하기 어렵기 때문에 Sass의 맵 구조를 채택했습니다. 이를 통해 라이트모드와 다크모드의 스타일을 아래와 같이 논리적으로 조직화할 수 있습니다

```scss
$light: (
  'text-primary': color('gray', 900),
  'surface-primary': color('gray', 100),
  'border-default': color('gray', 200),
);

$dark: (
  'text-primary': color('gray', 50),
  'surface-primary': color('gray', 900),
  'border-default': color('gray', 700),
);
```

#### **라이트/다크 모드 지원**

사용자마다 선호하는 모드가 다르므로 **개인의 편의성을 고려해 두 가지 모드를 모두 지원하는 것이 필수적**이라고 생각해 라이트/다크 모드를 모두 지원할 수 있도록 설계하였습니다.

**라이트 모드와 다크 모드 색상 정의**

아래의 `$light` 및 `$dark` 맵을 사용하여 **각 모드에서 사용될 색상을 정의했습니다.**

이렇게 정의하면 한 곳에서 색상 테마를 관리할 수 있어 유지보수가 편리합니다.

```tsx
$light: (
  'text-primary': color('gray', 900),
  'surface-primary': color('gray', 100),
  'border-default': color('gray', 200),
);

$dark: (
  'text-primary': color('gray', 50),
  'surface-primary': color('gray', 900),
  'border-default': color('gray', 700),
);
```

**CSS 변수로 변환하여 테마 적용**

각 모드에서 정의한 색상을 **CSS 변수로 변환**하여, **모드 전환을 유연하게 적용**할 수 있도록 하였습니다. 아래의 `@mixin theme($theme-name)`은 **Sass의 맵 데이터를 반복하여 CSS 변수로 변환**하는 역할을 합니다. 즉, `$light` 또는 `$dark` 맵을 전달하면 해당 값이 `--text-primary: #000000;` 같은 형식으로 CSS 변수에 자동으로 적용됩니다.

```tsx
@mixin theme($theme-name) {
  @each $key, $value in $theme-name {
    --#{$key}: #{$value};
  }
}
```

기본적으로 라이트 모드 색상이 설정됩니다. 만약 HTML 요소에 `data-theme="dark"` 속성이 추가되면 `:root[data-theme='dark']`가 활성화되면서 다크 모드 색상으로 변경됩니다. 이를 활용하면 JavaScript에서 `document.documentElement.setAttribute('data-theme', 'dark')`와 같은 코드를 실행하여 다크 모드를 동적으로 적용할 수 있습니다.

```tsx
:root {
  @include theme($light);  // 기본 테마는 라이트 모드 적용
}

:root[data-theme='dark'] {
  @include theme($dark); // 다크 모드가 활성화되면 다크 테마 적용
}
```

### **타이포그래피 시스템 구축**

디자인 시스템에서 **폰트 스타일을 일관되게 관리**하는 것이 중요합니다. Sass의 `map`, `function`, `mixin`을 활용하면 **폰트 크기, 굵기, 테마 색상 등을 중앙에서 정의하고 쉽게 변경할 수 있도록 설정하였습니다.**

#### **폰트 패밀리 설정**

폰트 패밀리는 **기본적으로 사용할 글꼴과 대체 글꼴을 지정하는 역할**을 합니다.

```tsx
$font-family:
  'Pretendard Variable',  // 기본 폰트
  Pretendard,
  -apple-system,
  BlinkMacSystemFont,
  system-ui,
  sans-serif;
```

* `'Pretendard Variable'`을 **기본 폰트**로 설정합니다.
* 만약 `'Pretendard Variable'`이 없으면, `Pretendard` 폰트를 사용합니다.
* 시스템 기본 폰트(`apple-system`, `BlinkMacSystemFont`, `system-ui` 등)를 순차적으로 사용합니다.
* 최종적으로 `sans-serif`를 사용해 **모든 환경에서 폰트가 정상적으로 렌더링**되도록 보장합니다.

#### **폰트 크기와 굵기 설정**

```tsx
$font-sizes: (
  'small': 1.2rem,
  'body': 1.6rem,
  'heading': 2rem,
);

$font-weights: (
  'regular': 400,
  'medium': 500,
  'bold': 700,
);
```

#### 폰트 스타일 가져오기

Sass의 `map`과 `function`, `mixin`을 활용하여 **일관된 폰트 스타일을 적용했습니다.**

```tsx
@function font($size, $weight: 'regular') {
  @return (
    'size': map.get($font-sizes, $size),
    'weight': map.get($font-weights, $weight)
  );

```

* 이 함수는 `map.get()`을 이용해 폰트 크기와 굵기를 반환합니다.
* 예: `$text-style: font(’16’, ‘bold’)` // 결과: ('size': 1.6rem, 'weight': 700)

#### 폰트 스타일 모음 정의

```tsx
$text: (
  'display-large': font('32', 'bold'),
  'body-large': font('16', 'regular'),
  'caption-small': font('12', 'regular'),
);
```

* 폰트 스타일(예: `display-large`, `caption` 등)을 한 곳에서 관리하도록 했습니다.
* `font()` 함수를 활용하여 크기와 굵기를 설정할 수 있습니다.
* 예: `map.get($text, 'display-large')` // 결과: ('size': 1.6rem, 'weight': 400)

#### **Mixin을 활용한 스타일 적용**

```tsx
@mixin text($variant) {
  $style: map.get($text, $variant); // 스타일 가져오기
  font-size: map.get($style, 'size');
  font-weight: map.get($style, 'weight');
}
```

* `@mixin text($variant)`는 `$text` 맵에서 해당 스타일을 가져와 적용합니다.
* `map.get($text, $variant)`를 이용해 `size`, `weight` 값을 가져옵니다.
* 예: `@include font-text(display-large);`

### **반응형 디자인과 여백 시스템**

```tsx
$mobile: 320px;
$tablet: 768px;
$notebook: 1024px;
$desktop: 1680px;
```

```tsx
// gap,margin,padding

$xxs: 0.4rem;
$xs: 0.8rem;
$sm: 1.2rem;
$md: 1.6rem;
$lg: 2.4rem;
$xl: 3.2rem;
$xxl: 4rem;
```

### **모듈화된 스타일 관리**

Sass의 `@use`와 `@forward`를 활용하면 **스타일을 모듈화**하여 유지보수를 쉽게 할 수 있습니다.

#### **1. `@use`와 `@forward`란?**

Sass에서 스타일을 여러 파일로 분리하고 효율적으로 관리하려면 **모듈화**가 필요합니다.

이를 위해 `@use`와 `@forward`를 사용합니다.

**`@use`**

* 다른 스타일 파일을 **가져와서 사용할 때** 사용됨
* `@import`와 다르게 **중복 로딩을 방지**하여 성능 최적화 가능

**`@forward`**

* **스타일 파일을 다른 파일에서 사용할 수 있도록 내보내는 역할**
* 여러 파일을 하나의 **메인 파일**로 통합할 때 유용

#### **2. 스타일 모듈화 예시**

```tsx
// _global.scss 
@forward './color-system' as color-*;
@forward './font-system' as font-*;
@forward './spacing-system' as space-*;
```

```scss
@use 'global' as *;

.button {
	padding: $space-md
}
```

### 결론

디자인 시스템을 구축하여 **일관된 UI 제공, 유지보수성 향상** 등의 효과를 얻을 수 있었습니다.

1. 디자인 토큰(Color, Typography, Spacing, Breakpoint)을 활용해 스타일을 체계적으로 관리&#x20;
2. 라이트/다크 모드를 CSS 변수로 구현하여 유연한 테마 변경 가능&#x20;
3. Sass의 모듈화 기능(@use, @forward)을 활용해 유지보수성을 극대화
