관련 커밋: 링크

다크모드 설정하기

나는 보통 밤에 블로그를 관리하므로, 블로그의 전반적인 테마가 어두웠으면 하는 바람이 있었다. 물론 단순히 어두운 테마를 사용해도 되는 일이긴 하지만, 그보다는 다크모드를 사용하고 싶었다. 이 글에서 방법을 찾았다.

우선 _config.yml 파일에서 다음과 같이 다크모드를 사용할 것임을 알린다. 또, 어떤 스킨을 다크모드로 사용할지를 알려줘야 한다. 나는 새로 custom-dark.scss 파일을 추가했다.

dark_theme                : true
dark_skin                 : "custom-dark"

그리고 assets/css/ 디렉터리로 들어가, 다음과 같이 main_dark.scss를 추가한다.

---
# Only the main Sass file needs front matter (the dashes are enough)
---

@charset "utf-8";

@import "minimal-mistakes/skins/custom-dark"; // skin
@import "minimal-mistakes"; // main partials

그 후 _includes/head.html로 들어가서, 위에서 지정한 dark_theme이 참이라면 방금 만든 main_dark.scss를 로드하도록 한다.

{% if site.dark_theme %}
  <link rel="stylesheet" href="/assets/css/main_dark.css">
{% endif %}

그리고 _layouts/default.html<head> 태그 내부에 다음의 코드를 붙여넣는다.

<style>
    .switch input[type="checkbox"],
    .switch .checked {
        display: none;
    }
    .switch input[type="checkbox"]:checked ~ .checked
    {
        display: inline-block;
    }
    .switch input[type="checkbox"]:checked ~ .unchecked
    {
        display: none;
    }
    label[for="toggle_dark_theme"] {
        position: relative;
        top: .15em;
    }
    .vl {
        border-left: 2px solid white;
        height: 1em;
    }
</style>

마지막으로 _includes/masthead.html에서 <a class="site-title"><ul class="visible-links"> 사이에 다음 코드를 넣어준다.

{% if site.dark_theme %}
<div style="margin-left: 5px; border: 2px solid #555; border-radius:10px; background-color:#222">
    <label class="switch" for="toggle_dark_theme" style="color:#bbb; font-size:1em; display:inline; margin-left:5px; margin-right:5px">
        <input type="checkbox" id="toggle_dark_theme" onclick="scrollbar()"/>
        <span class="material-icons md-16 unchecked" style="color:#ffbb9a">&#xE518;</span>
        <span class="material-icons md-16 checked" style="color:#ffeabc">&#xE51C;</span>
    </label>
</div>
{% endif %}

그럼 masthead에 버튼이 추가되었을 것이며, 이 버튼은 누를 때마다 해와 달이 번갈아 나온다. 하지만 아직 이 버튼의 행동을 지정하지 않았기 때문에 유의미한 변화는 어떤 것도 일어나지 않는다. assets/js/custom 폴더에 (물론 _config.yml에서 제대로 불러오기만 한다면 어디에 놓든 상관은 없다) 다음의 Javascript

    function darkmode(){

    var defaultTheme = [...document.styleSheets].find(style => /(main.css)$/.test(style.href))
    var darkTheme = [...document.styleSheets].find(style => /(main_dark.css)$/.test(style.href))

    if (darkTheme) {
        const darkModeCookie = document.cookie
            .split('; ')
            .find(co => co.startsWith('MDARK='))
        if (darkModeCookie !== undefined) {
            const dmodeValue = darkModeCookie.split('=')[1]
            darkTheme.disabled = dmodeValue !== 'Y'
            defaultTheme.disabled = dmodeValue === 'Y'
        } else {
            if (matchMedia('(prefers-color-scheme: dark)').matches) {
                darkTheme.disabled = false
                defaultTheme.disabled = true
            } else {
                darkTheme.disabled = true
                defaultTheme.disabled = false
            }
            document.cookie = `MDARK=${darkTheme.disabled ? 'N' : 'Y'}; path=/;`
        }

        let toggleThemeBtn = document.getElementById("toggle_dark_theme")
        if (toggleThemeBtn) {
            toggleThemeBtn.checked = defaultTheme.disabled
        }

        let changeTheme = () => {
            darkTheme.disabled = !darkTheme.disabled
            defaultTheme.disabled = !darkTheme.disabled
            document.cookie = `MDARK=${darkTheme.disabled ? 'N' : 'Y'}; path=/;`
        }

        toggleThemeBtn.addEventListener('click', changeTheme)
    }
    }

를 넣는다. 그 후 _layouts/default.html 파일의 <body class="layout-- ..."> 태그에 속성 onload="darkmode()"를 추가해주고, _config.yml의 항목 head_scripts:에 방금 만든 js파일을 추가해준다.

여기까지 완료하면 다크모드와 라이트모드를 왔다갔다 할 수 있게 되었다. 또, 처음 접속했을 때의 시스템 환경설정에 맞춰 다크모드인지 아닌지가 결정된다.

모양 다듬기

위 글에서 소개한 다크모드는 아주 잘 작동했지만, 몇 가지 모양을 다듬을 것이 있었다.

우선 나는 라이트 모드일 때에도 배경이 완전한 하얀색이 아니라 대다수의 그림들 (주로 diagram들)이 배경이 지워진 상태의, 검은 색이었는데 이런 그림은 다크모드로 전환하였을 때 거의 보이지 않는다는 문제가 있었다.

octahedral axiom

때문에 다크모드에서는 이런 그림들에 색상을 반전시켜줄 필요가 있어서, 이들 그림에 invert 클래스를 추가해준 후, _main-dark.scss 파일의 말미에 다음의 코드

img.invert {
  filter: invert(1);
}

를 추가해주었다.

octahedral axiom

잘 작동하는 것 같다.

또, 인라인 코드 블럭이 지난번부터 마음에 들지 않았는데, 다크모드에서의 인라인 코드 블럭 색상을 바꾸는 것보다 이들 태그를 _sass/minimal-mistakes/_pages.scss에서 수정하는 것이 좋아보였다.

  :not(pre) > code {
    padding-top: 0.1rem;
    padding-bottom: 0.1rem;
    font-size: 0.8em;
    background: $code-background-color;
    border-radius: $border-radius;

    &::before,
    &::after {
      letter-spacing: -0.2em;
      content: "\00a0"; /* non-breaking space*/
    }
  }

이렇게 되어 있던 코드를

  :not(pre) > code {
    padding-top: 0.1rem;
    padding-bottom: 0.1rem;
    font-size: 0.8em;
    background: mix($background-color, $text-color, 90%);
    border-radius: $border-radius;
    color: $text-color;

    &::before,
    &::after {
      letter-spacing: -0.2em;
      content: "\00a0"; /* non-breaking space*/
    }
  }

이렇게 수정했다.

스크롤바 꾸미기

마지막으로 스크롤바를 예쁘게 꾸미고 싶었다. 또, 이 스크롤바가 사이트가 라이트 모드인지, 다크 모드인지에 따라 달라지도록 만들려고 하였다.

우선 아까 _layouts/default.html<head> 태그 안에 넣은 <style> 태그에

body::-webkit-scrollbar{width: 16px;}
body::-webkit-scrollbar-track {background-color:#071734;}
body::-webkit-scrollbar-thumb:hover {background: #a9874a; background-clip: padding-box; border: 2px solid transparent}

를 추가한다. 또, 좌측 사이드바와 페이지 목차 또한 간혹 스크롤바가 생길 정도로 길어질 때가 있어서, 약간의 시행착오 끝에 다음을 추가하면 된다는 것을 알아냈다.

.sidebar.sticky::-webkit-scrollbar{width: 6px}
.sidebar.sticky::-webkit-scrollbar-track{display: none}
.sidebar.sticky::-webkit-scrollbar-thumb:hover {background: #071734; background-clip: padding-box; border: 1px solid transparent}

.toc__menu::-webkit-scrollbar{width: 6px}
.toc__menu::-webkit-scrollbar-track{display: none}
.toc__menu::-webkit-scrollbar-thumb:hover {background: #071734; background-clip: padding-box; border: 1px solid transparent}

의도적으로 -webkit-scrollbar-thumb을 비워뒀기 때문에 아직까지는 스크롤바 트랙 위에 스크롤바가 보이지 않는다. 이제 <style>태그가 끝난 직후에 <style> 태그를 하나 더 만들고, idscrollbar-color로 바꿔준다. 즉 다음 코드를 </style> 직후에 추가한다.

<style id="scrollbar-color">

</style>

이 태그 안에는 아무것도 없지만, Javascript를 이용하면 사이트가 로드될 때 이 태그 안의 내용물을 color scheme에 맞도록 해줄 수 있다. 다음 js를 assets/js/custom/ 안에 넣는다.

function scrollbar() {
if(document.getElementById("toggle_dark_theme").checked == true)
document.head.querySelector("#scrollbar-color").innerHTML=`
   body::-webkit-scrollbar-thumb {background-color:#455a64; border-radius: 3px; background-clip: padding-box; border:2px solid transparent}
   .sidebar.sticky::-webkit-scrollbar-thumb {background-color:#282828; border-radius: 3px; background-clip: padding-box; border:1px solid transparent}
   .toc__menu::-webkit-scrollbar-thumb {background-color:#282828; border-radius: 3px; background-clip: padding-box; border:1px solid transparent}
 `
 else
 document.head.querySelector("#scrollbar-color").innerHTML=`
   body::-webkit-scrollbar-thumb {background-color:#cfd8dc; border-radius: 3px; background-clip: padding-box; border:2px solid transparent}
   .sidebar.sticky::-webkit-scrollbar-thumb {background-color:#eaeaf2; border-radius: 3px; background-clip: padding-box; border:1px solid transparent}
   .toc__menu::-webkit-scrollbar-thumb {background-color:#eaeaf2; border-radius: 3px; background-clip: padding-box; border:1px solid transparent}
 `
 }

이제 _config.yml의 headscript에서 이 javascript 또한 불러오고, _layouts/default.html 파일의 <body class="layout-- ..."> 태그에서 scrollbar() 또한 불러오도록 하여 속성 onload="darkmode(), scrollbar()"으로 지정하면 된다.


참고자료

앞서 말한 것과 같이 다크모드 설정과 관련된 코드는 모두 이 글로부터 왔다. invert를 해 주는 것은 구글링을 통해 이 글을 찾았다. 스크롤바를 테마에 따라 바꾸는 것은 이리저리 삽질을 하다 만든 것이긴 하지만, 스크롤바 색상을 바꾸는 게 가능하다는 것은 이 글에서 확인했다.

댓글남기기