영감을 받다
여러분들은 컬러 팔레트를 만들어 보신 적 있으신가요? 저도 회사에서 디자이너와 협업하면서 컬러 팔레트를 만든 적이 종종 있었습니다. 환경과 기술에 따라 약간의 차이는 있을 수 있겠지만, 대부분 다음과 같은 방식으로 구현을 하실 겁니다.
// 주 색의 명도별로 RGB 색을 할당합니다. const ORANGE = { 50: '#fffaf0', 100: '#fff2e4', 200: '#ffe7d4', 300: '#ffc98f', 400: '#fea775', 500: '#fe7e43', 600: '#d97000', 700: '#9c4221', 800: '#7b341e', 900: '#652b19', };
RGB 값을 봐서는 이게 도대체 무슨 색을 의미하는지 알기 어렵습니다.
FFFAF0
이 도대체 무슨 색인지, 외우지 않고서는 금방 이해하기 힘들죠. 심지어 (디자인 시스템을 마련하는 도중과 같이) 이 색들을 변경해야 하는 일이 생긴다면, 어떤 값을 얼마나 변경해야 원하는 색을 만들 수 있는지 짐작하기 어렵습니다. 그러다가 저는 CSS 변수 합성의 강력함이라는 글을 읽게 되었습니다. 해당 글에서 소개하는 CSS 변수 합성을 통해 색에 명확한 의미를 부여하고, 색을 체계적으로 관리하는 방식이 충격적이었습니다. 심지어 해당 방식에서 활용하는 CSS 변수 합성은 Tailwind 에도 잘 어울립니다. 그래서 저는 이 방법을 개인 블로그를 만드는 과정에 도입해 보았습니다.
참고로 블로그 환경에는 Next.js 와 Tailwind 를 사용했습니다.
주 색상 정하기
제일 처음으로 할 일은 주 색상을 정하는 것입니다. 저는 옛날에 마비노기라는 게임을 했었는데요, 그때의 지향 색 중 하나인 “빕분”을 주 색상으로 정해 보았습니다.

해당 색상의 RGB 코드는
255, 170, 170
입니다. 하지만 우리가 원하는 것은 HSL 값이므로, HSL로 바꿔 봅시다. ColorHexa 라는 사이트에서 특정 색을 검색하면 다음과 같이 다양한 색 체계의 값들을 알려줍니다. HSL로는 0, 100%, 83.3%
네요.
주 색상 코드를 알았으니, 이제 CSS 파일에 색을 정의합니다. 우선 색과 채도를
--base-pink
로 명명합니다.// globals.css @theme { --base-pink: 0, 100%; }
남은 건 명도
83.3%
인데요, 저는 400으로 지정해 보겠습니다. 그리고 이 둘을 합쳐서 --color-pink-400
을 정의합니다.@theme { --base-pink: 0, 100%; --lightness-400: 83.3%; --color-pink-400: hsl(var(--base-pink), var(--lightness-400)); }
주 색상인 pink-400이 완성되었습니다!
다른 명도들 정하기
주 색상의 색과 채도, 명도가 정해졌으니 나머지 다른 명도들도 정의합니다. 아까의 HexaColors 페이지에서 스크롤을 내리다 보면 Tint Color Variation이 보입니다. 여기서 차례대로 색상들을 가져와 50부터 900까지의 명도를 정의하도록 하겠습니다.

조금 귀찮긴 하지만, 각 색상을 눌러 페이지를 들어가서 HSL 값들을 하나씩 땁니다. 예외가 있을 순 있지만, 제가 선택한 색상은 모두 색과 채도가 동일하므로 명도만 정의했습니다.
@theme { /* ... */ --lightness-50: 99%; --lightness-100: 98.4%; --lightness-200: 93.3%; --lightness-300: 88.4%; --lightness-400: 83.3%; --lightness-500: 78.4%; --lightness-600: 73.3%; --lightness-700: 68.4%; --lightness-800: 63.5%; --lightness-900: 58.4%; }
각 명도를 정의했으니, 기본 색과 명도를 조합합니다.
@theme { /* ... */ --color-pink-50: hsl(var(--base-pink), var(--lightness-50)); --color-pink-100: hsl(var(--base-pink), var(--lightness-100)); --color-pink-200: hsl(var(--base-pink), var(--lightness-200)); --color-pink-300: hsl(var(--base-pink), var(--lightness-300)); --color-pink-400: hsl(var(--base-pink), var(--lightness-400)); --color-pink-500: hsl(var(--base-pink), var(--lightness-500)); --color-pink-600: hsl(var(--base-pink), var(--lightness-600)); --color-pink-700: hsl(var(--base-pink), var(--lightness-700)); --color-pink-800: hsl(var(--base-pink), var(--lightness-800)); --color-pink-900: hsl(var(--base-pink), var(--lightness-900)); }
짜잔! 이것으로 주 색상의 팔레트가 완성되었습니다! 🎨 저는 블로그에 컬러 테마 변경 기능을 넣기 위해 색을 하나 더 골라서 팔레트를 만들었습니다.
@theme { /* ... */ --base-blue: 210, 100%; --color-blue-50: hsl(var(--base-blue), var(--lightness-50)); --color-blue-100: hsl(var(--base-blue), var(--lightness-100)); --color-blue-200: hsl(var(--base-blue), var(--lightness-200)); --color-blue-300: hsl(var(--base-blue), var(--lightness-300)); --color-blue-400: hsl(var(--base-blue), var(--lightness-400)); --color-blue-500: hsl(var(--base-blue), var(--lightness-500)); --color-blue-600: hsl(var(--base-blue), var(--lightness-600)); --color-blue-700: hsl(var(--base-blue), var(--lightness-700)); --color-blue-800: hsl(var(--base-blue), var(--lightness-800)); --color-blue-900: hsl(var(--base-blue), var(--lightness-900)); }
이제 이 HSL 체계에서 “색”을 바꾸고 싶다면
--base-...
에서 Hue 값만 변경하면 되고, “채도”를 바꾸고 싶다면 Saturation 값만 변경하면 됩니다. 너무 우아하지 않나요?컬러 팔레트를 다 만들었으니, 컬러 테마 변경 기능을 위한 밑작업을 합니다.
컬러 테마 변경 기능의 밑작업을 하기
만약 여러분이 블로그에 컬러 테마 변경 기능을 도입한다고 생각해 보세요. 현재 코드로 어떻게 하면 될까요?
<p className="text-pink-500">...</p>
만약 사용자가 컬러 테마를 바꾸는 버튼을 클릭하면 어떻게 해야 할까요? 음.. 모든 요소를 일일이 찾아서
text-pink-500
을 text-blue-500
으로 바꾸자니 난감하네요. 현재 컬러 테마에 따라 자동으로 바뀌게 할 수는 없을까요?main-color
라는 새로운 CSS 변수를 만들어서 해결해 봅시다.@theme { /* ... */ --color-main-50: hsl(var(--main-color), var(--lightness-50)); --color-main-100: hsl(var(--main-color), var(--lightness-100)); --color-main-200: hsl(var(--main-color), var(--lightness-200)); --color-main-300: hsl(var(--main-color), var(--lightness-300)); --color-main-400: hsl(var(--main-color), var(--lightness-400)); --color-main-500: hsl(var(--main-color), var(--lightness-500)); --color-main-600: hsl(var(--main-color), var(--lightness-600)); --color-main-700: hsl(var(--main-color), var(--lightness-700)); --color-main-800: hsl(var(--main-color), var(--lightness-800)); --color-main-900: hsl(var(--main-color), var(--lightness-900)); }
--main-color
가 무엇인지는 모르지만, 어찌 되었건 해당 값을 따르는 CSS 변수들을 정의했습니다. 이제 우리가 할 일은 컬러 테마에 따라 --main-color
만 변경시켜 주면 됩니다. 저는 여기서 tailwind 공식 문서의 data 속성을 이용해 다크 모드를 제어하는 방식을 차용했습니다.@base { html[data-theme="pink"] { --main-color: var(--base-pink); } html[data-theme="blue"] { --main-color: var(--base-blue); } }
export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="ko" data-theme="pink"> <body className="antialiased"> {/* ... */} </body> </html> ); }
html
요소에 기본 컬러 테마인 "pink"
를 지정하고, data-theme
의 값에 따라 --main-color
가 변하도록 만들었습니다. 이제 컬러 테마 변경 버튼만 만들면 끝입니다.컬러 테마 변경 버튼 만들기
CSS만으로 컬러 테마를 변경하는 방식을 구현하고 싶었지만, 도저히 불가능해서 결국 스크립트의 힘을 빌렸습니다. 자연스럽게 해당 컴포넌트는 클라이언트 컴포넌트가 되었습니다.
"use client"; export default function Header() { function changeColorScheme() { const $html = document.getElementsByTagName("html").item(0); if ($html) { $html.dataset.theme = $html.dataset.theme === "pink" ? "blue" : "pink"; } } return ( <header> <nav> <ul> <li> <button title="색 바꾸기" onClick={changeColorScheme} /> </li> {/* ... */} </ul> </nav> </header> ); }
동작은 단순합니다.
html
요소를 찾아서, theme
값을 토글합니다.이제 우리는 컬러 테마 기능을 완성했습니다! 실제 동작을 한번 볼까요?

잘 동작하네요!
이렇게 CSS 변수 합성과 HSL를 이용해 의미있고 우아한 색 체계를 만들고 Tailwind에 적용해보았습니다. 여러분들도 블로그에 CSS 변수와 HSL를 활용한 컬러 테마를 만들어 보시는 건 어떠신가요?