시스템이 없어도 화면은 만들어집니다. 문제는 그 화면이 늘어날 때 생깁니다. 시스템 없이 버티면 어떤 고통이 쌓이는지, 그리고 토큰과 컴포넌트가 그 고통을 어떻게 걷어 가는지 코드 비교로 보겠습니다.

34.1 같은 파랑이 화면마다 다르다

시스템이 없으면 사람마다 파랑을 눈대중으로 골라 적습니다. 분명 같은 색을 의도했는데 값이 조금씩 어긋납니다.


.header-link { color: #2563eb; }
.promo-badge { background: #2f6bed; }
.cta-button { background: #1e6fe0; }
.tab.active { border-color: #2661ea; }


네 곳 모두 우리 파랑이라 부르지만 실제 값은 넷 다 다릅니다. 나란히 놓기 전에는 아무도 눈치채지 못하다가, 한 화면에 모이는 순간 미묘한 얼룩처럼 드러납니다.

34.2 이름 하나로 불일치를 없앤다

이 값들을 토큰 하나로 묶으면 불일치가 태어날 여지 자체가 사라집니다. 고를 수 있는 파랑이 하나뿐이니까요.


:root {
--brand-blue: #2563eb;
}
.header-link { color: var(--brand-blue); }
.promo-badge { background: var(--brand-blue); }
.cta-button { background: var(--brand-blue); }
.tab.active { border-color: var(--brand-blue); }


이제 네 곳이 완벽히 같은 색입니다. 누가 새 화면을 만들어도 var(--brand-blue) 를 부를 뿐, 자기만의 파랑을 지어내지 않습니다.

34.3 값을 바꿀 때: 20군데 vs 1군데

브랜드 색을 보라로 바꾸라는 요청이 왔다고 해 봅시다. 하드코딩된 코드에서는 색이 박힌 모든 자리를 손으로 찾아 고쳐야 합니다.


.header-link { color: #7c3aed; } /* 고침 */
.promo-badge { background: #7c3aed; } /* 고침 */
.cta-button { background: #7c3aed; } /* 고침 */
/* ... 나머지 17군데도 하나씩 ... */


스무 곳을 고치는 동안 반드시 몇 군데는 빠뜨리고, 빠뜨린 자리만 옛 파랑으로 남아 버그가 됩니다. 토큰이 있으면 이 작업이 한 줄로 끝납니다.


:root {
--brand-blue: #7c3aed;
}


이름을 참조하던 모든 자리가 한꺼번에 보라로 갈아입습니다. 고칠 곳이 하나이니 빠뜨릴 곳도 없습니다.

34.4 새 버튼 만들 때: 복붙 지옥 vs 재사용

시스템이 없으면 버튼이 하나 더 필요할 때마다 기존 스타일을 통째로 복사해 붙입니다. 그렇게 복제된 버튼은 저마다 조금씩 어긋나기 시작합니다.


.newsletter-btn {
background: #2563eb;
color: #fff;
padding: 10px 16px;
border-radius: 6px;
border: none;
font-size: 14px;
cursor: pointer;
}
/* 다음 화면에서 또 복사, 값 하나만 슬쩍 바뀜 */
.signup-btn {
background: #2563eb;
color: #fff;
padding: 11px 16px;
border-radius: 6px;
border: none;
font-size: 14px;
cursor: pointer;
}


공용 .btn 클래스가 하나 있으면 이 복붙이 통째로 사라집니다. 새 버튼은 클래스를 부르기만 하면 됩니다.


.btn {
background: var(--brand-blue);
color: #fff;
padding: 10px 16px;
border-radius: 6px;
border: none;
font-size: 14px;
cursor: pointer;
}


<button class="btn">구독</button>
<button class="btn">가입</button>


버튼이 스무 개가 되어도 스타일 정의는 여전히 한 벌뿐입니다. 복사본이 없으니 서로 어긋날 일도 없습니다.

34.5 간격도 제각각이면 리듬이 깨진다

색만 흔들리는 게 아닙니다. 여백을 눈대중으로 잡으면 화면의 리듬이 미세하게 어긋납니다.


.section-a { margin-bottom: 22px; }
.section-b { margin-bottom: 20px; }
.section-c { margin-bottom: 25px; }


간격 토큰을 정해진 배수로 두면 이 어긋남이 정돈됩니다.


:root {
--space-4: 16px;
--space-6: 24px;
}
.section-a,
.section-b,
.section-c { margin-bottom: var(--space-6); }


이제 모든 구획이 같은 호흡으로 떨어집니다. 눈에 보이지 않는 격자가 화면 전체에 질서를 줍니다.

34.6 유지보수 비용이 눈에 보인다

시스템의 이득은 결국 시간입니다. 컴포넌트 토큰까지 이어 두면 버튼 하나의 규격을 바꾸는 일도 한 곳에서 끝납니다.


:root {
--btn-padding-y: 10px;
--btn-padding-x: 16px;
--btn-radius: 6px;
}
.btn {
padding: var(--btn-padding-y) var(--btn-padding-x);
border-radius: var(--btn-radius);
}


디자이너가 버튼을 조금 더 둥글게 하자고 하면 --btn-radius 값 하나만 바꿉니다. 화면 수백 곳의 버튼이 동시에 따라오고, 회귀 버그가 끼어들 틈이 없습니다.

34.7 일관성이 신뢰를 만든다

같은 기능이 늘 같은 얼굴을 하고 있으면 사용자는 한 번 익힌 것을 계속 써먹습니다. 이 일관성은 상태 처리까지 공용 코드에 담을 때 완성됩니다.


.btn:hover { filter: brightness(0.95); }
.btn:active { transform: translateY(1px); }
.btn:disabled {
opacity: .5;
cursor: not-allowed;
}
.btn[aria-pressed="true"] {
background: var(--brand-blue);
box-shadow: inset 0 0 0 2px #fff;
}


모든 버튼이 똑같이 눌리고 똑같이 흐려집니다. 사용자는 화면이 바뀌어도 버튼이 어떻게 반응할지 이미 알고 있고, 그 예측 가능함이 곧 신뢰가 됩니다.

34.8 새 동료가 하루 만에 합류한다

시스템이 없으면 새로 온 사람은 흩어진 화면을 뒤지며 우리 규칙을 눈치로 배웁니다. 토큰과 유틸리티 클래스가 있으면 정해진 재료를 손에 쥐여 줄 수 있습니다.


.text-muted { color: var(--color-text-muted); }
.gap-4 { gap: var(--space-4); }
.p-6 { padding: var(--space-6); }


<div class="card p-6">
<h3>주간 리포트</h3>
<p class="text-muted">지난 7일 요약</p>
</div>


새 동료는 색값이나 간격을 외울 필요 없이 이름 붙은 재료를 조합합니다. 첫날 만든 화면이 곧바로 우리 톤에 맞아떨어집니다.

34.9 정리

시스템이 필요한 이유는 화면 한둘에서는 보이지 않습니다. 화면이 스물이 되고 손대는 사람이 여럿이 될 때, 하드코딩은 불일치와 복붙과 스무 군데 수정이라는 세금을 매일 걷어 갑니다. 토큰 하나로 색을 묶고 공용 클래스로 형태를 묶으면 그 세금이 사라지고, 값 하나 바꾸는 일이 한 줄로 끝납니다. 일관성과 속도와 낮은 유지비는 그렇게 코드 구조에서 자연스럽게 흘러나옵니다.