CSS 변수로 다크·화이트 모드 전환 만들기 (깜빡임 없이)

다크·화이트 모드 전환은 색상을 CSS 변수로 모아 두고, html 태그의 속성 하나로 변수 값을 바꾸면 돼요. 이 사이트 오른쪽 위의 전환 버튼이 이 방식이에요.

1. 색상을 변수로 모으기

색을 요소마다 직접 쓰지 않고 변수로만 가리켜요. 모드가 바뀌면 변수 값만 달라져요.

:root {
  --bg: #0d1117;
  --text: #e6edf3;
  --accent: #f2b84b;
}
html[data-theme="light"] {
  --bg: #f6f8fa;
  --text: #1f2630;
  --accent: #9a5b00;      /* 흰 배경에서도 읽히도록 더 어둡게 */
}
body { background: var(--bg); color: var(--text); }
a { color: var(--accent); }

2. 화면이 그려지기 전에 모드 적용하기

이 부분이 핵심이에요. 스크립트를 페이지 맨 아래에 두면, 밝은 모드를 고른 사용자가 새로고침할 때 어두운 화면이 잠깐 보였다가 바뀌어요. head 맨 위에 짧은 스크립트를 넣어서 화면이 그려지기 전에 속성을 정해요.

// head 맨 위의 script 태그 안에 넣는다
(function () {
  var t = "dark";
  try {
    var s = localStorage.getItem("theme");
    if (s === "light" || s === "dark") { t = s; }
  } catch (e) {}
  document.documentElement.setAttribute("data-theme", t);
})();

3. 버튼으로 바꾸고 기억하기

document.addEventListener("click", function (e) {
  var btn = e.target.closest(".theme-toggle");
  if (!btn) { return; }
  var root = document.documentElement;
  var next = root.getAttribute("data-theme") === "light" ? "dark" : "light";
  root.setAttribute("data-theme", next);
  try { localStorage.setItem("theme", next); } catch (err) {}
  btn.setAttribute("aria-label", next === "light" ? "다크 모드로 전환" : "화이트 모드로 전환");
});

실수하기 쉬운 부분

  • 포인트 색을 그대로 쓰면 안 돼요. 어두운 배경에서 잘 보이던 노란색은 흰 배경에서 글자로 쓰면 거의 안 읽혀요. 밝은 모드용으로 더 어두운 색을 따로 정해야 해요.
  • 색을 직접 지정한 요소가 남아 있으면 깨져요. 본문 어딘가에 color: #fff가 박혀 있으면 밝은 모드에서 사라져요. 전부 변수로 바꿔야 해요.
  • 버튼은 진짜 button으로 만드세요. div에 클릭만 달면 키보드로 누를 수 없어요. aria-label도 현재 상태에 맞게 바꿔 줘야 해요.
  • localStorage는 실패할 수 있어요. 사생활 보호 모드에서는 오류가 나기도 해서 try로 감싸요.
  • 서버 캐시와 충돌하지 않아요. 모드를 서버가 아니라 방문자의 브라우저에서 정하기 때문에, 페이지를 캐시해도 문제가 없어요.

확인 범위

이 방식은 이 사이트에 적용해 전환, 새로고침 후 유지, 두 모드의 글자 대비를 확인했어요. 운영체제의 다크 모드 설정을 따라가게 하려면 prefers-color-scheme 확인을 2번 스크립트에 더하면 돼요. 그 부분은 여기서 시험하지 않았어요.

출처

MDN — Using CSS custom properties

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다