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

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

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

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

  1. 중복된 코드 증가

    • 동일한 스타일이 여러 곳에서 반복적으로 정의되면서 코드가 불필요하게 길어집니다.

    • 예를 들어, 여러 파일에서 .button { background-color: #0d7bff; } 같은 코드가 중복될 수 있습니다.

  2. 유지보수성 저하

    • 특정 스타일을 변경해야 할 때, 모든 관련 CSS 파일을 찾아 수정해야 합니다.

    • 예를 들어, 브랜드 색상을 변경하려면 수십 개의 CSS 파일을 일일이 수정해야 할 수도 있습니다.

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

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

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

색상(Color) 시스템 구축

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

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

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

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

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

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

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

// 예시 
$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)

@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의 맵 구조를 채택했습니다. 이를 통해 라이트모드와 다크모드의 스타일을 아래와 같이 논리적으로 조직화할 수 있습니다

$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 맵을 사용하여 각 모드에서 사용될 색상을 정의했습니다.

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

$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 변수에 자동으로 적용됩니다.

@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')와 같은 코드를 실행하여 다크 모드를 동적으로 적용할 수 있습니다.

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

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

타이포그래피 시스템 구축

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

폰트 패밀리 설정

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

$font-family:
  'Pretendard Variable',  // 기본 폰트
  Pretendard,
  -apple-system,
  BlinkMacSystemFont,
  system-ui,
  sans-serif;
  • 'Pretendard Variable'기본 폰트로 설정합니다.

  • 만약 'Pretendard Variable'이 없으면, Pretendard 폰트를 사용합니다.

  • 시스템 기본 폰트(apple-system, BlinkMacSystemFont, system-ui 등)를 순차적으로 사용합니다.

  • 최종적으로 sans-serif를 사용해 모든 환경에서 폰트가 정상적으로 렌더링되도록 보장합니다.

폰트 크기와 굵기 설정

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

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

폰트 스타일 가져오기

Sass의 mapfunction, mixin을 활용하여 일관된 폰트 스타일을 적용했습니다.

@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)

폰트 스타일 모음 정의

$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을 활용한 스타일 적용

@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);

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

$mobile: 320px;
$tablet: 768px;
$notebook: 1024px;
$desktop: 1680px;
// 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. 스타일 모듈화 예시

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

.button {
	padding: $space-md
}

결론

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

  1. 디자인 토큰(Color, Typography, Spacing, Breakpoint)을 활용해 스타일을 체계적으로 관리

  2. 라이트/다크 모드를 CSS 변수로 구현하여 유연한 테마 변경 가능

  3. Sass의 모듈화 기능(@use, @forward)을 활용해 유지보수성을 극대화

Last updated