다크 모드를 tone prop 으로 만들다, 색 토큰 값을 뒤집었다
화면 하나만 어둡게 하려다 앱 전체로 번졌다. 판을 두 벌 만드는 대신 토큰 값을 뒤집었고, 안 따라온 20곳이 튀어나왔다.
화면 하나만 어둡게 만들어 달라는 요구는 대개 화면 하나에서 안 끝난다.
2026-08-09 밤, 전시 관람 서비스의 첫 화면을 어둡게 바꾸기로 했다. 처음엔 정말 첫 화면 하나였다. 공유 컴포넌트에 판을 하나 더 달았다.
<ScreenHeader tone="dark" ... />
<ChatHeaderMenu tone="dark" />
컴포넌트 안은 이렇게 갈렸다.
className={dark ? "border-white/15 bg-dosn-black" : "border-line bg-background"}
첫 화면의 글자·카드·탭·바닥글을 전부 어두운 색으로 손으로 바꿨다. 잘 돌아갔다.
그런데 한 시간 뒤 결정이 바뀌었다. 첫 화면만이 아니라 앱 전체를 어둡게 하기로 했다.
세어 보고 멈췄다
같은 방식을 이어가면 되는 일처럼 보였다. 화면이 열 개면 열 개에 tone="dark" 를 달면 된다.
세어 봤더니 그 앱에서 색 토큰을 쓰는 자리가 약 700곳이었다. 그런데 멈춘 이유는 숫자가 아니라 앞으로 계속 드는 비용이었다.
- 판을 두 벌 들면 — 새 화면을 만들 때마다 "이건 어두운 판도 필요한가" 를 물어야 한다. 한 번 빠뜨리면 그 화면만 밝게 뜬다. 물어보는 일이 영원히 안 끝난다
- 값을 뒤집으면 — 묻는 일 자체가 사라진다. 화면 코드는 색을 「이름」으로만 부르고, 그 이름이 무슨 색인지는 한 곳이 정한다
두 번째로 갈아탔다. 팔레트 정의 파일 하나에서 이름은 그대로 두고 값만 바꿨다.
background #FAF9F5 → #212121
primary #333333 → #FFFFFF
line #E0E0E0 → #3A3A3A
cream #F0EEE6 → #2A2A2A ← 「살짝 뜬 면」이라는 역할은 그대로다
화면 코드는 한 줄도 안 고쳤다. 그리고 한 시간 전에 만든 두 벌(tone)은 지웠다. 만들다 만 게 아니라, 만들고 나서 필요 없어진 것이다.
재미있는 건 이 자리였다.
charcoal #141413 → #F0F0F0
charcoal 은 「제일 진한 색」이라는 뜻으로 쓰이던 이름이라, 뒤집힌 판에서는 「제일 밝은 색」이 된다. bg-charcoal text-background 로 짝지어 둔 뱃지는 둘 다 뒤집혀서 대비가 그대로 유지됐다. 이름이 색이 아니라 역할을 가리키고 있었기 때문이다.
안 따라온 20곳
값을 뒤집고 화면을 열어 보니 안 따라온 자리가 20곳 있었다. 전부 같은 종류였다.
style={{ backgroundColor: "#f0efec" }} // 사이드바 카드
className="bg-[#f5f4f0]" // 약관 상자
style={{ color: "#555555" }} // 흐린 글자
토큰을 안 거친 것들. 값을 뒤집어도 이것들만 혼자 밝게 떴다.
그런데 이게 하드코딩을 찾아내는 아주 좋은 검사이기도 했다. 평소엔 #f0efec 이 회색인지 크림색인지 아무도 신경 안 쓴다. 판을 뒤집는 순간 토큰을 안 쓴 자리만 정확히 튀어나온다.
가장 고약했던 건 이거였다.
className="... text-white bg-primary" // 흰 글자 + 흰 배경
primary 가 흰색이 되면서 버튼이 통째로 하얀 덩어리가 됐다. 토글 손잡이도 같은 병이었다 — 켜짐 상태의 트랙이 흰색인데 손잡이도 bg-white 라, 켜면 손잡이가 사라졌다.
전부 토큰으로 바꿨다. 손잡이는 트랙의 반대색으로 갈랐다.
두 벌인가, 한 벌을 뒤집는가
같은 화면을 두 가지 모습으로 보여줘야 할 때 갈리는 지점은 여기다. 모습을 두 벌 만들 것인가, 값을 한 벌로 바꿀 것인가.
두 벌은 지금 당장은 빠르다. 실제로 한 시간 동안 잘 돌아갔다. 대신 앞으로 만드는 모든 화면에 질문이 하나씩 붙는다. 값 한 벌은 처음에 이름을 잘 지어야 하지만, 그 뒤로는 묻지 않아도 된다.
그리고 이름이 색이 아니라 역할을 가리키고 있었는지는, 뒤집어 보면 그 자리에서 드러난다. charcoal 은 살아남았고, #f0efec 스무 곳은 살아남지 못했다.