다크모드
어느 날 블로그에 다크모드를 추가해야 겠다는 생각이 들었다. 다크모드가 있다면 깜깜한 곳에서 블로그를 볼 때 눈에 부담이 덜할 것이다. 별로 어렵지 않아 보였다. 다크모드 CSS를 따로 만들어 놓고 블로그에서 다크모드를 선택하면 CSS를 바꿔주면 그만 아닌가.
원래 CSS를 복사해 글자색과 배경색을 적절히 바꿔 다크모드 CSS를 만들었다. 다크모드가 있는 다른 웹 사이트의 다크모드를 참조해 CSS를 수정했다. 단순 작업이다. 내비게이션 바에 모드 전환 링크를 추가하고 약간의 JavaScript 코드를 추가했다.
랩탑에서 블로그를 띄워 간단히 테스트를 했다. 모드 전환 링크를 클릭하자 블로그가 다크모드로 바뀌었다. '예상대로 간단하군.' 그러나 그건 착각이었음이 바로 드려났다. 블로그의 다른 링크를 클릭하자 다크모드가 적용되지 않은 페이지가 표시됐다.
다크모드를 적용했으면 그 상태를 브라우저가 알고 있어야 한다. 그래야 다른 페이지를 로딩할 때 계속 다크모드를 적용할 수 있을 것 아닌가. 복잡한 일은 아니다. 브라우저의 로컬 스토리지에 모드 상태를 저장해놓고 페이지를 로딩할 때마다 모드에 따라 로딩할 CSS를 고르면 될 것 아닌가.
마크업과 JavaScript 코드를 조금 수정했다. 그런데 또 다른 문제가 생겼다. 페이지가 로딩된 직후 Javascript를 실행해 CSS를 바꾸다 보니 페이지가 깜박거렸다. 처음에는 라이트모드 CSS가 기본으로 포함되어 있기 때문에 그런 줄 알고 라이트모드 CSS를 제거해보기도 했다.
그러나 CSS를 지정하지 않아도 현상이 개선되지 않았다. CSS를 지정하지 않으니 디폴트 스타일로 페이지가 먼저 렌더링되고, 그 다음 JavaScript로 바꾼 CSS가 적용돼 페이지가 다시 표시되니 깜박거리는 것이었다. 여러 방법을 생각해 봤지만 해결책이 떠오르지 않았다.
다크모드를 접어야 하나 싶었다. 그러다 다크모드를 지원하는 블로그를 발견했다. 어떻게 했나 확인했더니, body
요소에 --
로 시작하는 속성을 잔득 넣어놓고 모드에 따라 값을 바꾸는 것이었다. 소스를 조금 더 살펴보니 CSS에서 var(--main-background)
와 같은 식으로 속성을 참조하는 게 보였다.
조금 찾아보니 이게 CSS 커스텀 속성으로 문서 여러 곳에서 사용할 값을 정의할 수 있는 개체라 한다. 어떻게 돌아가는지 대충 이해하고 나니 구현하는 것은 어렵지 않았다. CSS에서 색상이 들어가는 부분을 모두 찾아서 하나씩 속성으로 정의하고 다크모드에 어울릴 색상을 할당했다.
이렇게 겨우 블로그에 다크모드를 적용했다. 상단 내비게이션 바 맨 오른쪽에 모드 전환 링크를 추가했다. 내가 참고한 블로그에서는 모드 전환 아이콘에 CSS 애니메이션이 적용되어 있었지만, 그렇게까지 하는 건 오버인 것 같아 참았다. 그냥 유니코드에서 쓸만한 문자를 찾아 넣었다.
라이트모드일 때는 내비게이션 바에 달 모양(☾) 아이콘이 표시되며 이걸 클릭하면 다크모드로 바뀐다. 다크모드에서는 해 모양 아이콘(☀)이 표시된다. 달 모양과 해 모양 문자 폭이 조금 다른지 아이콘이 발뀔 때 메뉴 아이템이 울컥해 CSS를 조금 더 수정했다.
블로그를 재생성해 GitHub에 푸시한 후 확인해 보니 Disqus로 붙인 댓글에 문제가 생기는 게 보였다. 로컬에서 테스트할 때 확인할 수 없었던 부분이다. Disqus가 페이지에 로딩될 때 페이지 스타일에 어울리게 댓글을 렌더링해 추가하는데, 모드가 바뀐 경우에는 다시 로딩해야 할 것 같았다.
다행히 Disqus를 다시 로드하게 하는 것은 쉬웠다. 다음 함수를 추가하고 모드가 바뀔 때 호출해 Disqus를 다시 로드하도록 했다.
function resetDisqus() {
DISQUS.reset({reload: true});
}
이 정도면 보기 흉하지는 않은 것 같다.
그러나 코드 블록이 포함된 페이지를 보니 영 아니다. 임시로 배경색만 조금 어둡게 했는데, 문법 강조에 사용된 모든 색상을 다크모드에 맞게 바꾸는 것은 아마 문법 강조 스타일 하나를 새로 만는는 것과 마찬가지 노력이 필요할 것이다. 이 부분은 나중에 천천히 개선하는 게 좋겠다.