CSSのfilterプロパティとJavaScriptで手軽にダークモードに切り替える



昨今、多くのデバイスやブラウザの対応によって、Webサイトも目に優しいと言われているダークモードのデザインが求められるようになりました。

ダークモードとなると暗い色調のデザインをCSSで用意していくことになるので、既存のWebサイトでは対応に時間がかかるところですが、CSSのfilterプロパティを使うことで、既存のWebサイトも手軽にダークモードに切り替えることができます。

ダークモードの対応方法としては、CSS3のメディアクエリの特性のprefers-color-schemeを利用して、ダークモード用のCSSをがっつり用意する方法もありますが、CSSのfilterプロパティで対応すると、ほんの数行でダークモードのデザインに変えることができます。

prefers-color-schemeについては、以下でご紹介しています。

↓ ↓ ↓

CSS3のメディアクエリを利用してwebサイトをダークモードに対応させる

それでは、CSSのfilterプロパティを利用してダークモードに対応する方法を見ていきましょう。

ダークモード時のCSSの設定


簡単なサンプルでご紹介します。
まずはHTMLから。

HTML

<main>

  <div class="layout-block">

    <div class="block-l">
      <h2>Headline</h2>
      <img src="images/sample.jpg" alt="">
      <p>Example text... Example text... Example text... </p>
    </div>

    <div class="block-r">
      <h2>Headline</h2>
      <p>Example text... Example text... Example text... </p>
    </div>
      
  </div>

  <div id="btn">
    <input type="button" value="LightMode" onclick="lightMode();">
    <input type="button" value="DarkMode" onclick="darkMode();">
    <input type="button" id="changeMode" value="Light / Dark">
  </div>

</main>



3つのボタンをinput要素で用意しました。
2つはonclick属性を設定して、JavaScriptの関数を実行するように。
もう1つはクリックしてモードを切り替える、トグルスイッチとして利用するボタンになります。

2つの切り替えパターンは後述します。


続いてはCSSになります。

filterプロパティは、ぼかしや色変化などのグラフィック効果を要素に適用させることができます。
このfilterプロパティを使って色を変化させます。

CSS

:root[theme="dark"] {
  filter: invert(100%) hue-rotate(180deg);
}

:root[theme="dark"] img {
  filter: invert(100%) hue-rotate(180deg);
}

img {
  width: 100%;
  height: auto;
  margin: 14px 0;
}

main {
  height: 100vh;
  background: #fff;
}

h1 {
  text-align: center;
  padding: .6em
}

.layout-block {
  background: #e8e8e8;
  padding: 4%;
  display: flow-root;
}

.layout-block div {
  margin: 0 2%;
  padding: 2%;
}

.block-l {
  background: #1e90ff;
  float: left;
}

.block-r {
  background: #ee82ee;
  float: right;
}

.block-l, .block-r {
  width: calc(50% - 8%);
}

#btn, #p-link {
  padding: 1em;
}

input[type="button"] {
  padding: 8px 14px;
}



img以下の見た目のデザインは適当にご用意しました。

「:root」の部分は「html」としてもOKです。
:rootは文書のルートとなる要素、html要素を表します。

html要素(:root)のtheme属性の値がdarkである時に、filterプロパティで色を変化させます。
invert()関数は変換の度合いの設定になります。0%と100%の間で変換の度合いを指定していき、100%にすることで完全に反転します。
hue-rotate()関数は、色相を回転させます。色相環の円の360°で回転角を指定します。

「:root[theme=”dark”] img」では、画像も一緒に変化すると本来の綺麗な画像ではなくなってしまうので、色の変化を戻すために設定しています。

切り替えに時間的変化のアニメーションを加えたい場合は、transitionプロパティを使うと良いでしょう。

CSS

html {
  transition: color .5s, filter .5s;
}

:root[theme="dark"] {
  filter: invert(100%) hue-rotate(180deg);
}

:root[theme="dark"] img {
  filter: invert(100%) hue-rotate(180deg);
}



ほんの数行で、既存のWebサイトに対してダークモードに対応する設定ができます。


ここからはJavaScriptを使って、ボタンを利用したいくつかの切り替え方法を見ていきます。

ボタンでモードを切り替える


htmlのinput属性でいくつかボタンを用意しておきました。
ここでJavaScriptを使って、ボタンをクリックしてモードを切り替えるプログラムをご紹介します。

お好みの方法を試して、利用していだたければと思います。

ボタンをクリックしてモードを切り替えていきますが、ページを移動した際もモードの情報を保持するように、HTML5のWeb Storageも利用していきます。

Web Storageについては、以下でご紹介しています。

↓ ↓ ↓

Cookieよりも扱いやすい。HTML5で追加されたWeb Storage

Web Storageには「sessionStorage」と「localStorage」と2つのストレージが用意されていますが、保存データをウィンドウやタブを閉じるまで有効とするsessionStorageを利用していきます。

それでは見ていきましょう。

onclick属性


onclick属性が設定されたinput要素をクリックし、JavaScriptの関数を呼び出して実行させる方法では、以下のように関数を用意しておきます。

JavaScript

let sMode = window.sessionStorage.getItem('user');
let el = document.documentElement;
el.setAttribute('theme', sMode);

function lightMode() {
  document.documentElement.setAttribute('theme', 'light');
  window.sessionStorage.setItem('user', 'light');
}

function darkMode(){
  document.documentElement.setAttribute('theme', 'dark');
  window.sessionStorage.setItem('user', 'dark');
}



「document.documentElement」でdocumentのルート要素(html)に対して、setAttribute()メソッドを使ってtheme属性とその値(light / dark)をセットします。lightMode()が呼び出されたら「light」、darkMode()が呼び出されたら「dark」の値をtheme属性に指定します。

「window.sessionStorage.getItem」や「window.sessionStorage.setItem」では、セッションのデータ保持でページの移動前のモード情報を移動後に利用できるようにしています。

初めてアクセスした場合は、sessionStorageはnullとなるため、theme属性の値もnullとなります。
nullでも特に影響はありません。

もし、初めてアクセスした時でも、ユーザーの設定に合わせてダークモードに切り替える場合は、以下のようにします。

JavaScript

let userMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
let sMode = window.sessionStorage.getItem('user');
let el = document.documentElement;

if(sMode) { //sessionStorageにデータがある場合
  el.setAttribute('theme', sMode);
} else { //sessionStorageにデータがない場合
  if(userMod == true) { //ユーザーの設定がダークモードの時
    el.setAttribute('theme', 'dark');
  } else { //ユーザーの設定がライトモードの時
    el.setAttribute('theme', 'light');
  }
}

function lightMode() {
  el.setAttribute('theme', 'light');
  window.sessionStorage.setItem('user', 'light');
}

function darkMode(){
  el.setAttribute('theme', 'dark');
  window.sessionStorage.setItem('user', 'dark');
}



if文で、sessionStorageにデータがある場合は、保持しているデータをtheme属性の値にセットします。
sessionStorageにデータがない場合は、ユーザーがシステムで設定がライトモードかダークモードかを判別してtheme属性に値を設定します。
window.matchMedia(‘(prefers-color-scheme: dark)’).matches」では、ユーザーがシステムで設定しているカラーテーマを取得しています。ダークモードであればtrueを返します。

トグルスイッチで切り替える


1つのボタンでクリックして切り替えるのであれば、トグルスイッチ的な機能を実装します。
「Light / Dark」というボタンをクリックして、LightとDarkを切り替えてみます。

まずは、シンプルにtheme属性の有無でダークモードに切り替える方法です。
以下、サンプルコードです。

JavaScript

let el = document.documentElement;

document.getElementById("changeMode").onclick = function() {
  el.toggleAttribute('theme');
  if(el.hasAttribute('theme')) {
    el.setAttribute('theme', 'dark');
  }
};



「changeMode」のidが付いた要素のボタンをクリックした際に関数を実行します。

ボタンの要素がクリックした時に、toggleAttribute()メソッドでtheme属性を付けたり消したりします。
if文では、hasAttribute()メソッドでtheme属性を持っているかを条件として、theme属性を持っていればdarkの値を設定します。
「theme=”dark”」がある状態で、ダークモードに適応させるという内容です。

上記のプログラムでは、ページが移動した際に元の色に戻ります。

こちらも先ほどと同じように、sessionStorageでデータを保持しながら、ユーザーのカラーテーマに合わせたデザインを適応させてみます。

以下、サンプルコードです。

JavaScript

let userMod = window.matchMedia('(prefers-color-scheme: dark)').matches;
let sMode = window.sessionStorage.getItem('user');
let el = document.documentElement;

if(sMode) {
  el.setAttribute('theme', sMode);
} else {
  if(userMod == true) {
    el.setAttribute('theme', 'dark');
  } else {
    el.setAttribute('theme', 'light');
  }
}

document.getElementById("changeMode").onclick = function() {
  let nowMode = el.getAttribute('theme');
  if(nowMode == 'dark') {
    el.setAttribute('theme', 'light');
    window.sessionStorage.setItem('user', 'light');
  } else {
    el.setAttribute('theme', 'dark');
    window.sessionStorage.setItem('user', 'dark');
  }
};



onclickの関数のプログラムの前は、先ほどと同じようにデータの保持や現在のモードの情報でtheme属性を設定しています。
onclickの関数内では、現在のモードが何かによってtheme属性にどちらにセットするかを処理しています。
その時一緒に、sessionStorageにもデータを保存します。

以下、実際の動作になります。
動画(3分半)



問題なくボタン操作で色が変わっているのが確認できます。


JavaScriptは慣れですが、CSSの記述はすごくシンプルかと思います。

既存のWebサイトを手軽にダークモードに対応させたい時には、ぜひ参考にしてください。