예전에 메모해놓고 이제 게시글로 적는다!
기본 배경 색 없애기
먼저 css레벨에서 적용되는 css를 초기화해야한다.
브라우저는 기본적으로 css가 없을 시 페이지 이동할 때 이전 페이지의 배경색을 그대로 유지한다.
\theme\icarus\css\include\style\base.styl
7줄 기본 배경색 none으로 수정하기
1
| $body-background-color ?= none;
|
기존 js파일을 두 개로 나누기
로컬스토리지를 읽고 다크모드를 적용하는 함수와 html을 전부 로드한 후 버튼의 innerText를 수정하는 함수로 나누었다.
다크모드를 적용하는 함수는 render blocking이 이루어져야하고 버튼의 innerText의 수정은 HTML이 모두 로드 후 이루어져야하기 때문이다.
따라서 버튼을 수정하는 함수는 defer로 불러오고 다크모드를 확인하고 적용하는 함수는 속성 없는 script태그로 불러온다.
\themes\icarus\source\js\darkmode.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function init() { const darkScheme = window.matchMedia("(prefers-color-scheme:dark)"); const theme = localStorage.getItem("theme"); if (theme === "dark") { document.body.classList.add("dark"); return; } if (theme === "light") { return; }
if (darkScheme) document.body.classList.add("dark");
localStorage.setItem("theme", darkScheme ? "dark" : "light"); }
|
hexo\themes\icarus\source\js\darkmodebutton.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| const darkModeButton = document.querySelector("#changeModeButton"); const darkScheme = window.matchMedia("(prefers-color-scheme:dark)");
darkScheme.addEventListener("change", (e) => { console.log("hidark"); const newColorScheme = e.matches ? "dark" : "light"; localStorage.setItem("theme", newColorScheme);
if (newColorScheme === "dark") { document.body.classList.add("dark"); btn.innerText = "🌙"; return; } document.body.classList.remove("dark"); btn.innerText = "🌞"; });
function toggleTheme() { console.log("hibutton"); document.body.classList.toggle("dark"); darkModeButton.innerText = document.body.classList.contains("dark") ? "🌙" : "🌞"; localStorage.setItem( "theme", document.body.classList.contains("dark") ? "dark" : "light" ); }
function initButton() { console.log("initButton"); const data = localStorage.getItem("theme"); if (data == "dark") { darkModeButton.innerText = "🌙"; return; } darkModeButton.innerText = "🌞"; }
initButton(); darkModeButton.addEventListener("click", toggleTheme);
|
\themes\icarus\layout\common\scripts.jsx
56번쨰 줄에 darkmodebutton.js추가
1 2
| <script src={url_for("/js/main.js")} defer></script> <script src={url_for("/js/darkmodebutton.js")} defer></script>
|
hexo\themes\icarus\layout\common\head.jsx
js를 로드하고 실행하는 동안 렌더링을 막아야하기 때문에 script에 속성을 지정하지 않아야한다.
적다보니 preload속성을 추가해도 좋을 것 같다.
1
| <script src={url_for("/js/darkmode.js")}></script>
|
고의로 render blocking 만들기
새로고침이 되어서 다크모드가 적용되기 전 까지 렌더링이 이루어지면 안된다.
body의 최상단에 darkmode.js에서 정의한 init함수를 호출해준다.
hexo\themes\icarus\layout\layout.jsx
1 2 3 4
| <html lang={language ? language.substr(0, 2) : ""}> <Head site={site} config={config} helper={helper} page={page} /> <body class={`is-${columnCount}-column`}> <script>init();</script>
|
ref
https://www.youtube.com/watch?v=ElsZ-v4Ow08