CONTENTS
ナビバーに追加した2つのボタン
見た目で大体予想は付くだろうとは思いますがを押すと明るい配色のライトモードに切り替わり、を押すとデフォルトのダークモードに戻るという機能のボタンです。
実装に当たり参考にしたのはこちらのサイト。調べたら他にも様々なスクリプトや実装方法がありましたが、こちらで紹介されてるコードが一番シンプルでわかりやすかったです。
ダークモードに任意で切り替えられるボタンをCSSとJavascriptで作ろう! | STROBOLIGHTS.tokyo (Wayback Machine)
導入のきっかけ
個人的に、白画面が眩しく感じるようになってきたのとデザイン的にも好みだったのでずっとダークテーマにしていたものの、暗い画面よりも明るい画面の方が好み & 見やすいという方もいるだろうし、ライトモードという選択肢も用意した方が親切だろうなと思いつつ、面倒くさそうなのでずっと保留にしていました。
最近たまたま、Blogger 独自の CSS テーマデザイナーの代わりになる カスタムプロパティというのを知ってテスト導入してたんですが、カスタムプロパティを使えば個別ページや HTML / JavaScript ウィジェット内の <style> にも変更内容が自動的に適用できるし、ライトモード用の CSS の設定もしやすくなるということがわかり、2種類の CSS を用意してみる気になったというわけなんです。
ちなみに当ブログのライトモード用の CSS はこちら。元々のデザインがシンプルなせいもありますが、たったこれだけで済んじゃうんですw
この20数行を上書きするとライトモードに変わります。カスタムプロパティってほんと便利ですね(^^;
:root { --bg1: #e5e5ff; --bg2: #fbfbff; --bg3: #f0f0ff; --bg4: #e0e0ff; --bg1-t: rgba(229, 229, 255, .8); --shadow: #bbb; --brand: dodgerblue; --subbrand: coral; --color: #333; --darkcolor: #666; --lightcolor: #fff; --negacolor: #fff; --link: dodgerblue; } #header { background-color: var(--brand); } #header-text { color: var(--lightcolor); } .search-box-form { background: var(--bg2); } .mrp-post { background: var(--bg2)!important; }
ライトモードに切り替わるタイミングに関して、当初は prefers-color-scheme のメディアクエリでOS側の設定に合わせてダーク/ライトが自動で切り替わる仕様でいくつもりだったけど、訪問者の好みで自由に切り替えられるようにしたらもっと便利になるんじゃないかなと思い、ボタンによる切替式にしました。
機能について
まだ機能的に不十分で色々突っ込みどころもあるかもしれませんが、その辺はご容赦くださいw
例えば、ページ遷移やリロードをするとデフォルトのダークモードに戻ってしまうことや、ライトモードのボタンを押してから明るい画面に切り替わるまで若干のタイムラグがあることなど…。
間を置いて明るくなるのは、ライトモード用の CSS ファイルを外部(Googleドライブ)に置いてるため読み込みが遅くなってしまうせいなんですが、この挙動ってなんとなく蛍光灯を点けた時の感じに似ててこれはこれで趣があっていいな思うんだけどどうでしょう?w
選択状態を保持させるのは JavaScript でクッキーを制御(ブラウザに記憶)させればできるらしいけど、調べてもいまいち理解できなかったので諦めましたw
ボタンもナビバーと一緒に着いてくるので、どの位置にいてもいつでも切り替えられるということで不便はないと思いますけど。
もし要望があれば改善も検討はしますが、私は現状で十分満足してますのであまり期待はしないでください(^^;
カスタマイズの詳細は
当ブログ独自のカスタマイズ箇所との兼ね合いもあり、あまり参考にならないと思いますので詳細は割愛します。興味のある方はご自身で調べてトライしてみてくださいね。
無知な私でも出来たのでさほど難易度は高くないはずw
2021/04/10 追記: 別のスクリプトに変更しました
ライトモード導入方法に関して調べ始めた時、最初にこちらの記事を見つけて良さそうだなと思ったものの、ちょっと素人にはハードル高そうな気がして手も付けずに一旦パスしてたのですが、ダメ元でやってみたところ上手く出来そうだったのでこちらに乗り換えることにしました。
Qiita(@whike_chan さん)で紹介されているコードをベースにして、SANOGRAPHIX さんのカスタマイズ方法を参考に、カスタムプロパティで CSS を切り替えるようにしています。
SANOGRAPHIX Blogこのブログをダークモードに対応する - SANOGRAPHIX Blogなんとかは黒に染まれ、とかなんとか すでにお気づきの方もいらっしゃるかもしれないが、このブログにダークモードを追加した。https://text.sanographix.net/entry/enable-dark-mode
Qiitaサイトにダークモード切り替えボタンを置こう - Qiitahttps://qiita.com/whike_chan/items/3fff6d0c78fa74253d4d
当初のスクリプトとの仕様の違い
- prefers-color-scheme により初回訪問時は閲覧者のデバイスのモードに合わせてダーク/ライトが自動で切り替わる。
- 選択したモードはページ遷移やリロードしても保持される。(クッキー有効時)
- ライトモードの CSS も HTML 内にあるためボタンを押すと瞬時に切り替わる。
- ボタンを押すたびにとが回転して入れ替わる。(→回転を無効化させました)
1~3は理想通りの仕様にできて満足なんですが、4のボタンが回転するというちょっと癖のある挙動がなんか微妙な気もしなくはないですw
SANOGRAPHIX さんみたいなシンプルに切り替わるボタンにできたら最高なんですけど、スクリプトを弄って何とかするのは私にはまだ無理そうです(^^;
というわけで、回転させるための transition:transform を削除するという単純な方法で回転を無効化させましたw
当ブログ独自カスタマイズのコードとデモ (2022/08/21: HTML と CSS を改良しました)
参考までにコードを載せておきます。
環境によって設置位置等も異なり、微調整やカスタムプロパティの設定も必要になりますので各自で対応してください。
JS はほぼそのままですが、HTML と CSS はだいぶ改造しています。
See the Pen Mode Switch Demo by Fujiyan (@fujiyanx) on CodePen.
2021/06/08 追記: 埋め込みツイートのテーマの明暗も切り替え可能に
スクリプトを弄って Twitter の埋め込みコンテンツのテーマの明暗も切り替わるようにしてみました。
但し…ボタンを押しただけでは駄目で、その後リロードしないと反映されません(^^;
埋め込みツイートのテーマは、ローカルの CSS ではなく、Twitter の外部 JS からデータを読み込んでいるため、どうしてもこういう仕様になってしまうようです。
明暗スクリプトをさらに弄れば即反映できるようになるのかな?…いずれにしても自力では無理そうなのでやりませんけどねw
新仕様の切り替えボタン、何とか実装できました。https://t.co/MHGP4rLKsX
— ふじやん (@fujiyanx) 2021年4月10日
改造箇所について
真似される方がいるかどうかは分かりませんが、一応参考までに詳細を書いておきます。
メタタグ
まず、<head>~</head> 内に Twitter のテーマ用のメタタグを設置します。
ちなみに元はこういうタグで、以下のように変更しました。(id は別に何でも構いません)
<meta content='light' name='twitter:widgets:theme'/>
↓↓
<meta content='light' id='twth' name='twitter:widgets:theme'/>
JavaScript
赤文字の部分を追記しました。
const checkToggle = document.getElementById('js_mode_toggle'); const rotateIcon = document.getElementById('js_rotate'); const isLight = window.matchMedia('(prefers-color-scheme:light)').matches; const keyLocalStorage = 'modekey'; const localTheme = localStorage.getItem(keyLocalStorage); const twTheme = document.getElementById('twth'); let nowRotate = 0; if (localTheme === 'light') { rotateInfinite(); changeMode('light'); } else if (localTheme === 'dark') { changeMode('dark'); } else if (isLight) { rotateInfinite(); changeMode('light'); } checkToggle.addEventListener('change', function (e) { rotateInfinite(); if (e.target.checked) { changeMode('light'); localStorage.setItem(keyLocalStorage, 'light'); } else { changeMode('dark'); localStorage.setItem(keyLocalStorage, 'dark'); } }); function changeMode(mode) { if (mode === 'light') { document.documentElement.setAttribute('data-theme-mode', 'light'); twTheme.setAttribute('content', 'light'); checkToggle.checked = true; } else if (mode === 'dark') { document.documentElement.setAttribute('data-theme-mode', 'dark'); twTheme.setAttribute('content', 'dark'); checkToggle.checked = false; } } function rotateInfinite() { nowRotate += 180; rotateIcon.style.transform = 'rotate(' + nowRotate + 'deg)'; }
ボタンで明暗を切り替える毎に、id で指定したメタタグ内に content='light' または content='dark' の属性が挿入される仕組みになっています。
2024/07/17 追記
ChatGPT さんにコードを整理してもらいました。
F-lightユーザーでこちらのコードに変えたい方は、テーマ編集にて <!-- モードスイッチ
の下の方にある<script>/*<![CDATA[*/
~/*]]>*/</script>
の所のコードを下記のものと入れ替えてください。
const checkToggle = document.getElementById('js_mode_toggle'); const rotateIcon = document.getElementById('js_rotate'); const twTheme = document.getElementById('twth'); const keyLocalStorage = 'modekey'; const localTheme = localStorage.getItem(keyLocalStorage); const isLight = window.matchMedia('(prefers-color-scheme: light)').matches; let nowRotate = 0; const applyTheme = (mode) => { document.documentElement.setAttribute('data-theme-mode', mode); twTheme.setAttribute('content', mode); checkToggle.checked = (mode === 'light'); }; const rotateInfinite = () => { nowRotate += 180; rotateIcon.style.transform = `rotate(${nowRotate}deg)`; }; if (localTheme === 'light' || (localTheme === null && isLight)) { rotateInfinite(); applyTheme('light'); } else { applyTheme('dark'); } checkToggle.addEventListener('change', (e) => { rotateInfinite(); const mode = e.target.checked ? 'light' : 'dark'; applyTheme(mode); localStorage.setItem(keyLocalStorage, mode); });
圧縮版
const checkToggle=document.getElementById("js_mode_toggle"),rotateIcon=document.getElementById("js_rotate"),twTheme=document.getElementById("twth"),keyLocalStorage="modekey",localTheme=localStorage.getItem(keyLocalStorage),isLight=window.matchMedia("(prefers-color-scheme: light)").matches;let nowRotate=0;const applyTheme=e=>{document.documentElement.setAttribute("data-theme-mode",e),twTheme.setAttribute("content",e),checkToggle.checked="light"===e},rotateInfinite=()=>{nowRotate+=180,rotateIcon.style.transform=`rotate(${nowRotate}deg)`};"light"===localTheme||null===localTheme&&isLight?(rotateInfinite(),applyTheme("light")):applyTheme("dark"),checkToggle.addEventListener("change",e=>{rotateInfinite();let t=e.target.checked?"light":"dark";applyTheme(t),localStorage.setItem(keyLocalStorage,t)});
匿名さん、これなら文句ないでしょw
2024/10/14 追記: 別仕様のコードの紹介
むーなかさんにコメントにて別仕様のコードをご提供頂きました。
こちらのコードはで最後に選択していたモードを記憶するのではなく、PCやスマホのOSのモードに合わせて明暗が切り替わるようになります。(もちろん閲覧中にで別モードに変えることも可能です)
F-lightユーザーでこちらのバージョンに変えたい方は、テーマ編集にて <!-- モードスイッチ
の下の方にある<script>/*<![CDATA[*/
~/*]]>*/</script>
の所のコードを下記のものと入れ替えてください。
const checkToggle = document.getElementById('js_mode_toggle'); const isLight = window.matchMedia('(prefers-color-scheme: light)').matches; function changeMode(mode) { if (mode === 'light') { document.documentElement.setAttribute('data-theme-mode', 'light'); checkToggle.checked = true; } else if (mode === 'dark') { document.documentElement.setAttribute('data-theme-mode', 'dark') checkToggle.checked = false; } } if (isLight) { changeMode('light'); } else { changeMode('dark'); } checkToggle.addEventListener('change', function (e) { if (e.target.checked) { changeMode('light'); } else { changeMode('dark'); } });
圧縮版
const checkToggle=document.getElementById("js_mode_toggle"),isLight=window.matchMedia("(prefers-color-scheme: light)").matches;function changeMode(e){"light"===e?(document.documentElement.setAttribute("data-theme-mode","light"),checkToggle.checked=!0):"dark"===e&&(document.documentElement.setAttribute("data-theme-mode","dark"),checkToggle.checked=!1)}isLight?changeMode("light"):changeMode("dark"),checkToggle.addEventListener("change",function(e){e.target.checked?changeMode("light"):changeMode("dark")});
コメントを投稿
別ページに移動します7 件のコメント (新着順)
ふじやん
>むーなかさん
お返事遅くなってしまってごめんなさい。
わざわざ改良版のコードを書いていただいたようでありがとうございます。
私自身はOSはPCもスマホも常時ダークモードにしているのですが、拙ブログや他のサイトでも時間帯などによって切り替えているため今の仕様で満足していましたけど、確かにむーなかさんのようにOSに連動して自動で切り替わる仕様を望む人もいるかもしれませんね。
ということで早速記事に追記させて頂きました。
尚コードは自動で整形してくれるウェブサービスでインデントを付けてもらいました(^^)
ところで↓の匿名氏のいう「汚いコード」ってインデントの有無というより、無駄な処理だらけってことかと思ってましたけど、どうなんでしょうかねえ(^^;
あ、それとBloggerのコメントでは行頭の空白は無視されますので   等で明示的に空ける必要があります(^^;
むーなか
コメントに投稿したらインデントは全て削除された様です😅
むーなか
ふじやんさん、こんにちは。
最近、使用しているデバイスを全てライトモードとダークモードが時間帯で自動で切り替わる様にしたら夜よく眠れるようになり、とても気持ちがいいです。
そんな中で自分のブログを見た時に、いつも前回の表示形式で表示されるのが気になってくるようになってしまいました。以前は常にダークにしていたため気づかなかったのですが…。いつでもダークが好きな人は端末からダークにしているはずですし、端末設定によって切り替わる設定でもいいのではないかと思っています。
自分はそのようにしたいと思い、そこでこちらのコードでは前回設定を保存しているのが不要であると感じる様になりました。
また、参照コード元は太陽と月の絵文字を交互に回すために複雑な関数を使っていますが、F-Lightでは回るアニメーションは無いため、この関数は全く不要と感じました(今までこの様な表記になっていたことは全く知りませんでしたが…)。
自分の様に、端末の設定で切り替わって欲しい、端末に前回の表示方法を保存させたくない人向けのコードを書いてみました。
やっていることがぐっと分かりやすくなったのではないかと思います。
また、関数実行のコードが関数定義より前に書かれているのも分かりにくいので変えました。さらに、「匿名」氏(失礼な方ですな…)の発言も踏まえインデントをしておきました。
このコードの場合HTMLのlabelのID "js_rotate"は無意味なので消すと良いのではないかと思います。
お役に立つ日が来ます様に。
const checkToggle = document.getElementById('js_mode_toggle');
const isLight = window.matchMedia('(prefers-color-scheme: light)').matches;
function changeMode(mode) {
if (mode === 'light') {
document.documentElement.setAttribute('data-theme-mode', 'light');
checkToggle.checked = true;
} else if (mode === 'dark') {
document.documentElement.setAttribute('data-theme-mode', 'dark')
checkToggle.checked = false;
}
}
if (isLight) {
changeMode('light');
} else {
changeMode('dark');
}
checkToggle.addEventListener('change', function (e) {
if (e.target.checked) {
changeMode('light');
} else {changeMode('dark');
}
});
ふじやん
> 匿名さん
私は JavaScript に関しては殆ど知識がなく勉強する気もありませんので、きれいとか汚いとか言われてもわからないですし気にもなりません。
とりあえず動けばそれでOKというスタンスです。
匿名
コードが汚すぎる
ふじやん
LiveBlogger 씨, 이 블로그를 칭찬해 주시고 감사합니다.
문장 쪽은 변변치 않습니다만, 어떠한 참고가 되면 다행입니다.
LiveBlogger
안녕하세요. 블로그가 참 깨끗하고 깔끔하네요. 잘 보고 갑니다. 좋은 하루 되세요!