0354

FE

[CSS] CSS 변수와 Tailwind로 디자인 시스템 구축하기

| 서론: “이 버튼 색깔만 살짝 바꾸면 되는데…”

안녕하세요 팡일입니다.

우리는 흔히 프로젝트가 커질수록 컴포넌트는 수십, 수백 개로 늘어나고, 처음에는 단순했던 스타일 작업도 점점 복잡해집니다. 예를 들어, “우리 서비스의 포인트 컬러를 조금 더 밝게 바꿔볼까?”라는 기획 변경이 들어왔다고 상상해봅시다.

모든 컴포넌트의 버튼·헤더·아이콘 색상이 #5A67D8처럼 하드코딩되어 있다면? 우리는 grep과 sed의 달인이 되어 수십 개의 파일을 열고 수정하는 지옥의 여정을 떠나야 합니다.

저의 re-log 프로젝트도 똑같은 문제를 겪고 있었습니다.

  • 컴포넌트마다 스타일이 제각각 정의되어 있고

  • 사소한 디자인 변경에도 많은 파일을 수정해야 하는 구조였으며

  • 전체적인 디자인 일관성도 떨어지는 상태였습니다.

이 문제를 해결하기 위해, 저는 CSS 변수 + Tailwind CSS 조합으로 스타일을 중앙관리하는 디자인 시스템을 구축하기로 결정했습니다.

| 본론: 두 단계로 진행된 스타일 리팩토링 여정

1) 1단계: CSS 변수로 ‘진실의 원천(Single Source of Truth)’ 만들기

가장 먼저 한 일은 프로젝트 전반에서 공통으로 사용할 디자인 토큰을 한 곳에 모으는 것이었습니다. SvelteKit의 전역 스타일 파일 src/app.css에 CSS 변수를 정의하고, 이를 프로젝트 전체의 기준점으로 삼았습니다.

CSS
/* src/app.css */
:root {
    /* Colors */
    --color-primary: #4a5568;
    --color-secondary: #718096;
    --color-accent: #2c5282;
    --color-background: #f7fafc;
    --color-white: #ffffff;
    --color-black: #000000;
    --color-text-dark: #2d3748;
    --color-text-light: #f7fafc;

    /* Font Sizes */
    --font-size-xs: 0.75rem;
    --font-size-sm: 0.875rem;
    --font-size-base: 1rem;
    --font-size-lg: 1.125rem;

    /* Box Shadows */
    --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
    --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
}

이제 어디에서든 var(--color-primary)처럼 일관된 스타일 값을 참조할 수 있습니다. 포인트 컬러를 바꾸려면 app.css에서 단 한 줄만 고치면 되는 구조가 완성된 것이죠.

2) 2단계: Tailwind CSS와 함께 점진적으로 적용하기

CSS 변수를 기반으로 스타일의 기준점이 생겼다면, 다음 단계는 각 컴포넌트를 새로운 시스템에 맞게 리팩토링하는 일이었습니다.

이때 Tailwind CSS의 유틸리티 클래스가 큰 도움이 됐습니다.

아래는 DetailCard.svelte 컴포넌트의 리팩토링 전후 비교입니다.

(1) Before: <style> 블록 속 수많은 CSS

HTML
<!-- DetailCard.svelte (리팩토링 전) -->
<div class="card">
    <!-- ... -->
</div>

<style>
.card {
    background-color: white;
    border-radius: 0.5rem;
    box-shadow:
        0 4px 6px -1px rgb(0 0 0 / 0.1),
        0 2px 4px -2px rgb(0 0 0 / 0.1);
    padding: 2rem;
}

@media (width < 40rem) {
    .card {
        padding: 1rem;
        border-radius: 0;
    }
}
</style>

(2) After: Tailwind + CSS 변수로 간결하게

HTML
<!-- DetailCard.svelte (리팩토링 후) -->
<div
    class="w-full rounded-lg bg-white p-8 shadow-md sm:p-4 sm:rounded-none"
    style="background-color: var(--color-white); box-shadow: var(--shadow-md);"
>
    <!-- ... -->
</div>

<!-- <style> 블록은 이제 비어 있습니다! -->

Tailwind의 반응형 유틸리티(sm:p-4, sm:rounded-none) 덕분에 복잡한 미디어 쿼리도 훨씬 깔끔해졌습니다. 이 방식을 기반으로 RegisterForm, HeroSection 등 다른 주요 컴포넌트도 지속적으로 리팩토링했습니다.

| 결론: 이제 스타일 변경은 두렵지 않아!

CSS 변수와 Tailwind를 활용한 이번 스타일 리팩토링은 단순히 코드를 정리하는 수준을 넘어, 프로젝트 전체의 품질과 개발 효율을 크게 끌어올리는 계기가 되었습니다.

얻은 이점은 명확합니다.

  • 일관성 확보
    : 모든 컴포넌트가 동일한 디자인 토큰을 공유하므로 전체 UI의 통일성이 극대화되었습니다.

  • 유지보수 비용 감소
    : 포인트 컬러 등 글로벌 스타일 변경이 필요할 때 app.css 한 곳만 수정하면 끝입니다.

  • 개발자 경험(DX) 향상
    : CSS와 Svelte 파일을 오가던 불편함이 줄어들고, HTML 구조와 스타일을 한눈에 보며 개발할 수 있게 되었습니다.

만약 지금 스타일 때문에 골머리를 앓고 있는 프로젝트가 있다면, CSS 변수로 스타일 기준을 확립하고 Tailwind 같은 유틸리티 프레임워크로 점진적 개선을 시작해 보시길 추천드립니다. 디자인 시스템은 결코 대규모 프로젝트만의 전유물이 아닙니다. 작은 노력으로도 일관성 있고 유지보수 가능한 UI 기반을 만들 수 있습니다.