블로그: 테마 5개 만들기 — CSS Variables 하나로
블로그: 테마 5개 만들기에 대해 "왜?"라고 물으면 답할 수 있으신가요?
\n\n> 블로그: 테마 5개 만들기에 대해 "왜?"라고 물으면 답할 수 있으신가요?\n블로그에 다크 모드 하나쯤은 있어야 하지 않나 싶어서 시작했는데, 만들다 보니 욕심이 생겨서 5개까지 늘어났습니다. Dracula, GitHub Dark, Monokai, Solarized, One Dark — 전부 개발자들이 좋아하는 에디터 테마에서 따왔습니다.
근데 5개 테마를 관리하는 게 생각보다 어렵지 않았습니다. CSS Variables 하나로 끝났거든요.
핵심 아이디어
테마가 바뀌면 뭐가 달라져야 할까요? 결국 색상 입니다. 레이아웃이 바뀌는 건 아니고, 배경색·글자색·강조색만 달라지면 됩니다.
그러면 CSS에서 색상을 직접 쓰는 대신 변수로 빼고, 테마마다 변수 값만 바꿔주면 되지 않을까?
/* 컴포넌트에서는 변수만 참조 */
.header {
background: var(--bg);
color: var(--fg);
border-bottom: 1px solid var(--border);
}
/* 테마별로 변수 값을 다르게 정의 */
[data-theme="dracula"] {
--bg: #282a36;
--fg: #f8f8f2;
--border: #44475a;
--accent: #bd93f9;
}
[data-theme="github-dark"] {
--bg: #0d1117;
--fg: #c9d1d9;
--border: #30363d;
--accent: #58a6ff;
}
이렇게 하면 테마 전환은 <html> 태그의 data-theme 속성만 바꾸면 됩니다. 자바스크립트로 할 일이 거의 없습니다.
변수 설계
테마에서 관리하는 변수를 정리하면 대략 이런 구조입니다.
:root {
/* 기본 색상 */
--bg: ...; /* 배경 */
--fg: ...; /* 기본 텍스트 */
--fg-muted: ...; /* 흐린 텍스트 (날짜, 부가 정보) */
/* 강조 색상 */
--accent: ...; /* 링크, 버튼, 활성 상태 */
--accent-hover: ...; /* 호버 시 */
/* 구분선 */
--border: ...;
--border-light: ...;
/* 코드 블록 */
--code-bg: ...;
--code-fg: ...;
/* 터미널 */
--terminal-bg: ...;
--terminal-fg: ...;
--terminal-prompt: ...;
}
변수 이름을 지을 때 --dracula-purple 같은 테마 종속적인 이름 대신, --accent 같은 역할 기반 이름을 쓰는 게 포인트입니다. 컴포넌트에서 var(--accent)를 쓰면 어떤 테마든 자연스럽게 적용되니까요.
5가지 테마
Dracula
[data-theme="dracula"] {
--bg: #282a36;
--fg: #f8f8f2;
--accent: #bd93f9;
--border: #44475a;
--code-bg: #1e1f29;
}
보라색 강조가 특징입니다. 기본 테마로 쓰고 있습니다.
GitHub Dark
[data-theme="github-dark"] {
--bg: #0d1117;
--fg: #c9d1d9;
--accent: #58a6ff;
--border: #30363d;
}
GitHub 다크 모드 그대로입니다. 파란색 계열이라 깔끔합니다.
Monokai
[data-theme="monokai"] {
--bg: #272822;
--fg: #f8f8f2;
--accent: #a6e22e;
--border: #3e3d32;
}
초록색 강조. 서브라임 텍스트 쓰던 사람한테 익숙한 조합입니다.
Solarized Dark
[data-theme="solarized"] {
--bg: #002b36;
--fg: #839496;
--accent: #268bd2;
--border: #073642;
}
눈이 편한 파란 계열. 채도가 낮아서 오래 봐도 피로감이 적습니다.
One Dark
[data-theme="one-dark"] {
--bg: #282c34;
--fg: #abb2bf;
--accent: #61afef;
--border: #3e4452;
}
VS Code 기본 테마에 가까운 느낌입니다.
테마 전환 로직
JavaScript에서 해야 할 일은 딱 두 가지입니다.
<html>태그의data-theme속성 변경- 선택한 테마를
localStorage에 저장 (새로고침해도 유지)
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}
// 초기 로드 시
const saved = localStorage.getItem('theme') || 'dracula';
setTheme(saved);
이게 전부입니다. CSS Variables가 알아서 나머지를 처리합니다.
테마 선택 UI
헤더에 테마 선택 드롭다운을 넣었습니다. 클릭하면 5개 테마가 나오고, 선택하면 즉시 적용됩니다.
구현은 간단한데, 한 가지 신경 써야 할 점이 있습니다. 초기 로딩 시 깜빡임(FOUC) 문제입니다.
React가 마운트되기 전에 기본 테마가 잠깐 보이다가 저장된 테마로 바뀌면 화면이 번쩍합니다. 이걸 막으려면 index.html의 <head>에서 React보다 먼저 테마를 설정해야 합니다.
<script>
const t = localStorage.getItem('theme') || 'dracula';
document.documentElement.setAttribute('data-theme', t);
</script>
이 스크립트가 CSS보다 먼저 실행되면 깜빡임이 없습니다.
왜 CSS-in-JS 안 쓰고 CSS Variables를 선택했나
styled-components나 Emotion으로도 테마를 구현할 수 있는데, CSS Variables를 선택한 이유가 있습니다.
- ** 런타임 비용이 없음** — CSS Variables는 브라우저가 네이티브로 처리합니다. JS 런타임이 개입하지 않아서 빠릅니다.
- ** 번들 크기** — CSS-in-JS 라이브러리를 추가할 필요가 없습니다.
- ** 단순함** — 테마 전환이
setAttribute한 줄입니다. Provider 감싸고, Theme 객체 만들고 하는 보일러플레이트가 없습니다.
개인 블로그 수준에서는 CSS Variables가 가성비 최고입니다.