https://idea-hack.com/blog/107032/
CSSを使ってダーク/ライトモード切替ボタンを作る

CSSを使ってダーク/ライトモード切替ボタンを作る

基本的なCSSとJavaScriptだけでダークモードを実装する方法を紹介します。

ユーザーに対してカスタマイズ可能なユーザーインターフェースを提供することはUXの向上につながります。

最近はダークモードがトレンドの入りの兆しがあり、メジャーなサービスや各種ブラウザーがダークモードを取り入れ始めています。

私が開発しているWordPressテーマ「Brandia」もこのトレンドに従い、ダークモードを実装する予定です。

しかし、私もダークモード実装の経験があるわけではなかったので、まずは静的HTMLページ上でどのようにダークモードを実現すれば良いかを理解したいと思います。

前提

今回実装するダークモードの仕様は下記の通りとします。

  • 極力簡単なCSSコードでデザインを作成
  • 切り替えボタン実装のためにJavaScriptを使う
  • 切り替えの目印となるCSSクラス名をHTMLに付与する
  • ブラウザストレージに設定を保存させる
  • ページ読み込み時にブラウザストレージから設定を読み込ませる

それでは、開発を行いましょう。

CSSの実装を開始

今回はカスタムプロパティを利用して実装を行います。カスタムプロパティに詳しくない方のために、解説を引用しておきます。

カスタムプロパティ (CSS 変数やカスケード変数と呼ばれることもあります) は、 CSS の作者によって作成され、文書全体で再利用可能な特定の値を含むエンティティです。それらは、カスタムプロパティ記法 (たとえば、--main-color: black;) によって設定し、 var() 関数 (たとえば、 color: var(--main-color);) を使ってアクセスします。

MDN 公式サイトより

まず最初に、私はルート用の疑似要素:rootにスタイルを追加します。これはライトモード時のカラー設定をグローバルに適用したいからです。

:rootはドキュメントツリー(DOM)のルート要素の疑似要素として扱われる特別な要素名で、通常はHTML要素に適用されます。

CSS
:root {
    --primary-color: #302AE6;
    --secondary-color: #536390;
    --font-color: #424242;
    --bg-color: #fff;
    --heading-color: #292922;
}

次に、ダークモード向けのCSSを用意します。

CSS
[data-theme="dark"] {
    --primary-color: #9A97F3;
    --secondary-color: #818cab;
    --font-color: #e1e1ff;
    --bg-color: #161625;
    --heading-color: #818cab;
}

[data-theme="dark"]とはなんでしょうか?

これを理解するにはHTMLのカスタムデータ属性について理解しておく必要があります。

data-* グローバル属性 はカスタムデータ属性と呼ばれる属性の組を作り、HTML と、スクリプトによる DOM 表現との間で、固有の情報を交換できるようにします。

MDN公式サイトより

この場合は、data-themeというカスタム属性の値がdarkの時に適用するCSSです。

ここまでで、ライトモードとダークモード時のカスタム変数が完成しましたので、下記の様に、定義されたCSS変数をコーデイングしていきます。

CSS
body {
    background-color: var(--bg-color);
    color: var(--font-color);

    /*other styles*/
    .....
}

h1 {
    color: var(--secondary-color);

    /*other styles*/
    .....
}

a {
    color: var(--primary-color);

    /*other styles*/
    .....
}

HTMLを準備

ダークモードとライトモードの切り替えにはチェックボックスが最適です。私はこのチェックボックスをそのまま使うのではなく、下記のCSSを適用してモダンなものにしています。

Output
Pug
.theme-switch-wrapper
		label.theme-switch(for="checkbox")
			input#checkbox(type="checkbox")
			.theme-switch-background.theme-switch-icon-round
SCSS
.theme-switch-wrapper {
	display: flex;
	align-items: center;
	.theme-switch {
		display: inline-block;
		height: 34px;
		position: relative;
		width: 60px;
		input {
			display: none;
			&:checked {
				+ {
					.theme-switch-background {
						background-color: #576574;
						&:before {
							transform: translateX(26px);
						}
					}
				}
			}
		}
		.theme-switch-background {
			background-color: #ccc;
			bottom: 0;
			cursor: pointer;
			left: 0;
			position: absolute;
			right: 0;
			top: 0;
			transition: .4s;
			&:before {
				background-color: #fff;
				bottom: 4px;
				content: "";
				height: 26px;
				left: 4px;
				position: absolute;
				transition: .4s;
				width: 26px;
			}
		}
		.theme-switch-icon-round {
			border-radius: 34px;
			&:before {
				border-radius: 50%;
			}
		}
	}
}

これで切り替えボタンのHTMLマークアップも完了です。

JavaScriptを準備

それでは、最後にJavaScriptを用意して、ダークモード切替ボタンの実装を行います。

私が必要な作業は下記の3つです。

  • 切り替えボタンの際に生じるイベントに対応するイベントハンドラーの追加
  • 同じユーザーが次回サイトのページを読み込んだ時に設定を引き継ぐようにユーザーのブラウザに設定を保存
  • ユーザーが次回サイトのページを読み込んだ時に、既存の設定が存在するか確認し、結果に応じて表示を自動で切り替える。

イベントハンドラーの追加

JavaScript
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');

function switchTheme(e) {
    if (e.target.checked) {
        document.documentElement.setAttribute('data-theme', 'dark');
    }
    else {
        document.documentElement.setAttribute('data-theme', 'light');
    }    
}

toggleSwitch.addEventListener('change', switchTheme, false);

data-theme属性をCSSで追加しているので、この様にdocument.documentElement.setAttribute('data-theme', 'dark');の様なコードを記載することで、ダークモードとライトモードの切り替えが可能です。

ブラウザに設定を保存

ここまでで機能自体は完成しました。しかし、ユーザーがページを再読み込みするたびにライトモードに戻すべきではありません。そこで、ダークモードに変更したときに、設定をブラウザーのローカルストレージに保存します。

これを行うには先ほどのコードを下記の様に変更しましょう。

JavaScript
const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');

function switchTheme(e) {
    if (e.target.checked) {
        document.documentElement.setAttribute('data-theme', 'dark');
        localStorage.setItem('theme', 'dark'); //add this
    }
    else {
        document.documentElement.setAttribute('data-theme', 'light');
        localStorage.setItem('theme', 'light'); //add this
    }    
}

toggleSwitch.addEventListener('change', switchTheme, false);

これで、ユーザーストレージに「Theme」という名称でライト/ダークモードに関する設定が保存されるようになりました。

設定の読み込み

JavaScript
const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;

if (currentTheme) {
    document.documentElement.setAttribute('data-theme', currentTheme);

    if (currentTheme === 'dark') {
        toggleSwitch.checked = true;
    }
}

ページ読み込み時に、ローカルストレージからライト/ダークモードに関する情報を取得して反映させます。

完成

これで完成となります。せっかくなので、デモページをCodePenで公開しています。

KAZUKI

私は基本的にページ内にデモも記載するようコーデイングするのですが、さすがにHTML要素全体に影響するデモコードはCodePenを使うしかないですね・・・

See the Pen CSSを使ってダーク/ライトモード切替ボタンを作る by KAZUKI (@k_kikuchi_tw) on CodePen.