고객사 A는 파란색, 고객사 B는 주황색 브랜드를 원합니다. 첫 화면의 버튼 색만 바꾸는 동안에는 쉬워 보입니다. 시간이 지나면 알림 배너, 그래프, 포커스 테두리, PDF, 이메일에 색이 흩어집니다. 어느 화면은 A의 로고에 B의 색이 남고, 신규 기능은 기본 테마로만 출시됩니다. 고객사별 테마를 화면 곳곳의 조건문으로 구현하면 브랜드 요구가 늘수록 제품 자체가 여러 갈래로 갈라집니다. 해법은 공통 컴포넌트와 의미 기반 디자인 토큰을 분리하는 것입니다.
색상 코드가 아니라 역할을 이름 붙인다
#2874D0 같은 값이나 ‘파란색 버튼’이라는 이름으로는 기능이 늘어날 때 일관성을 지키기 어렵습니다. 대신 기본 행동, 위험 행동, 성공 상태, 본문 글자, 배경, 경계선, 포커스 표시처럼 화면에서 맡는 역할로 토큰을 정의합니다. 고객사별 테마는 그 역할에 대응하는 실제 색과 서체·로고 자산을 제공합니다. 버튼 컴포넌트는 ‘기본 행동 색’을 참조하므로 고객사마다 코드를 분기할 필요가 없습니다. MDN의 CSS 사용자 정의 속성 안내처럼 CSS 변수는 이런 값을 한곳에 정의하고 재사용하는 데 적합합니다.
토큰은 원시 값과 의미 값을 나누면 관리하기 쉽습니다. 원시 값은 코랄 색조의 여러 단계처럼 팔레트 자체이고, 의미 값은 ‘주요 버튼 배경’처럼 용도입니다. 다크 모드나 고객사 테마를 바꿀 때는 의미 값의 연결만 바꿉니다. 여백, 모서리, 글자 크기까지 모두 고객이 임의로 조정하게 하는 것은 신중해야 합니다. 색상과 로고는 달라져도 정보 계층과 상호작용 규칙은 같은 제품으로 유지하는 편이 테스트와 유지보수에 유리합니다.

테마 설정은 테넌트 데이터이자 운영 정책이다
테마를 URL 쿼리나 브라우저 저장소에만 맡기면 고객사 전환 때 이전 고객의 로고가 잠깐 보일 수 있습니다. 서버가 현재 인증된 고객사를 결정하고 해당 테마 버전을 내려주어야 합니다. 고객사 A의 관리자가 고객사 B의 테마 파일을 수정할 수 없어야 하므로 설정 API에도 테넌트 경계와 권한 검사를 적용합니다. 로고 이미지와 폰트 파일은 승인된 형식·크기로 제한하고, 외부 임의 CSS나 스크립트를 업로드해 실행하지 않게 합니다. 기본 테마는 설정이 누락됐거나 일부 값이 잘못돼도 읽을 수 있는 안전한 대체값이어야 합니다.
브랜드 색상이 접근성을 자동 보장하지는 않습니다. 진한 파란 배경 위의 회색 글자처럼 보기에는 세련돼도 읽기 어려운 조합이 생깁니다. 본문, 버튼 글자, 경고 메시지, 포커스 표시를 실제 배경과 짝지어 검사해야 합니다. WCAG 2.2의 명도 대비 기준을 참고해 테마별 조합을 검증하고, 색상만으로 성공·실패를 구분하지 않도록 아이콘과 텍스트도 함께 둡니다. 로고의 원래 색상은 유지하더라도 버튼 배경까지 무조건 같은 색을 써야 하는 것은 아닙니다. 브랜드 요구와 읽기 쉬운 인터페이스가 충돌하면 쓰임별 보조 색을 함께 합의해야 합니다.
다크 모드와 고객사 테마를 동시에 지원한다면 조합 수가 늘어납니다. 고객사별 색을 밝은 배경에만 맞춰 놓고 어두운 화면에 그대로 적용하면 대비가 무너질 수 있습니다. 각 테마의 밝은 모드와 어두운 모드를 별도 의미 토큰 세트로 만들고, 사용자 선호를 바꿔도 로고·그래프·상태 표시가 일관되게 보이는지 확인합니다.

새 컴포넌트를 출시할 때 테마도 함께 검사한다
테마가 늘수록 신규 화면 하나를 여러 고객사에서 살펴봐야 합니다. 모든 조합을 사람이 매번 열어 보기는 어렵지만 주요 컴포넌트의 스냅샷과 대비 검사, 누락 토큰 검사로 많은 문제를 자동으로 잡을 수 있습니다. 고객사 테마 변경은 미리보기와 승인, 적용 시각, 이전 버전으로 되돌리기를 갖추면 안전합니다. 이메일·내보낸 PDF처럼 웹 CSS를 공유하지 않는 출력물에는 같은 의미 토큰을 별도 렌더러로 전달해야 합니다. 마지막으로 새 고객사를 추가할 때 코드 배포가 필요한지 점검하세요. 테마 설정만으로 안전하게 표현할 수 있다면 제품은 하나로 유지되고 브랜드는 고객별로 달라집니다.