ダークモードでブラックサンタクロースを召喚してみた

UI開発者 矢尾

この記事はミツエーリンクスアドベントカレンダー2019 - Qiitaの11日目の記事です。

突然ですが、皆さんは「ダークモード」を使っていますか? 筆者はつい最近、スマートフォンをダークモードに切り替え、6年間使い続けていた無地の白背景が黒になりました。 このダークモードが世のユーザーに広く使われ始めたのは、今年の9月に公開されたiOS13の話題性からだと考えられます。

おそらく、

  • 暗い場所で使用する際に明るい画面と暗い夜道の明暗差を抑え、目の負担を軽減してくれる
  • ディスプレイに有機ELを採用するスマホの普及により、バッテリーの消費を抑えられる
  • YouTube、Twitter、Google Mapsなどのサービスがダークモードに対応したこと
  • 純粋にかっこいいから

などの理由で使用されている方が多いのではないでしょうか。やはり黒い画面はクールでかっこいいですからね。

今回のもくろみ

さて、本題です!

今回はタイトルにもあるとおり、クリスマスの象徴でもあるサンタクロースがダークモードのときにだけブラックサンタクロースに変貌してしまうページを作ってみたいと思います!

ブラックサンタ(クネヒト・ループレヒト)とは、ドイツに伝わるクリスマスの伝承です。悪い子に意地悪や連れ去ることから恐怖の存在とされてますが、実は極めて善人だと思います。 ブラックサンタクロース(黒サンタクロース)が来る「悪い子」の条件

Webでダークモードの適用をしてみよう

そもそも、Webページでダークモードの適用は可能なのでしょうか?

その答えは「YES」です。

意外にもCSSやJavaScriptを使ったシンプルな方法で適用ができます。
それでは、どのようにしてダークモードを適用するのか、その基本的な方法を紹介します。

CSSのメディアクエリを使って適用する

メディアクエリprefers-color-schemeを使うことでCSSでのダークモードの適用ができます。

@media (prefers-color-scheme:dark) {
/* ダークモード向けのスタイル */
}

上記に関しては過去のフロントエンドBlogにも取り上げられています。

近づくダークモード対応の足音 | フロントエンドBlog | ミツエーリンクス

しかし、各モード用に記述を分けていくことになるため、行数もその分多くなってしまいメンテナンス性やパフォーマンスの低下にもつながります。

そのため下記のようにCSS変数(カスタムプロパティ)を使用するなど、記述をできるだけ完結にしていく工夫が必要になってきます。

:root {
  --text: #444;
  --bg: #fff;
}
@media (prefers-color-scheme: dark) {
  :root {
    --text: #ddd;
    --bg: #444;
  }
}
body {
  color: var(--text);
  background-color: var(--bg);
}

JavaScriptの.matchMedia()を使って適用する

.matchMedia()の引数にprefers-color-schemeを渡すことで、CSSのメディアクエリのように条件分岐ができます。

const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)').matches;
const change = () =>{
    if (darkModeMediaQuery) {
        // ダークモードのときにbodyに.darkを付与
      document.body.classList.add('dark');
    } else {
      // ダークモードでないときbodyの.darkを外す
      document.body.classList.remove('dark');
    }
};

change();// 初期値の処理実行
darkModeMediaQuery.addListener(change);

ダークモードでブラックサンタクロースを召喚できるページを作ってみよう

今回ページを作成するにあたっての条件は以下になります。

  • ページを訪れたときにデバイスのカラーモードの判定を行う
  • ライトモードとダークモードでサンタクロース(コンテンツ)を出し分ける
  • ダークモードのときに背景を暗くする

では各ファイルの中身をご紹介します。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>ダークモードでブラックサンタクロースを召喚してみた</title>
</head>
<body>
<div class="str-section">
<img src="images/santaclaus_white.svg" alt="" class="santaImg">
</div>
</body>
</html>

CSS

CSSは少し長いので、ポイントを絞って説明します。

*{margin:0;padding:0;box-sizing:border-box}.santaImg{max-width:25pc;margin:auto;padding:0 20px;position:absolute;right:0;bottom:10px;left:0;width:90%}:root{--bg:transparent;--bgBlend:none}@media(prefers-color-scheme:dark){:root{--bg:#333;--bgBlend:luminosity}}.str-section{background-image:url(images/bg.jpg);background-repeat:no-repeat;background-size:cover;min-height:100vh;position:relative;background-color:var(--bg);background-blend-mode:var(--bgBlend)}

背景画像の色を変える

/* 雪イラストの背景 */
:root {
  --bg: transparent;
  --bgBlend: none;
}
@media (prefers-color-scheme: dark) {
  :root {
  --bg: #333;
  --bgBlend: luminosity;
  }
}
.str-section {
  background-image: url(images/bg.jpg);
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 100vh;
  position: relative;
  background-color: var(--bg);
  background-blend-mode: var(--bgBlend);
}

背景をダークモード用に書き出して表示を切り替えてもよいのですが、ダークモードのときに背景を暗くすることが今回の条件だったのでbackground-blend-modeを使ってモノクロの背景で切り替わるようにしました。 background-colorbackground-blend-modeをCSS変数で定義しています。

JavaScript

const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const img = document.querySelector('.str-section .santaImg');
const santaBlack = 'images/santaclaus_black.svg';
const santaLight = 'images/santaclaus_white.svg';
const changeSanta = () => {
    if (darkModeMediaQuery.matches) {
        // ダークモードに属性値を書き換えてブラックサンタクロースの画像にする
        img.src = santaBlack;
    } else {
        // ダークモードでないときは普通のサンタクロースの画像にする
        img.src = santaLight;
    }
};

changeSanta();// 初期値の処理実行
darkModeMediaQuery.addListener(changeSanta);

window.matchMediaでダークモードかどうかを判定し、img要素を取得してダークモードのときに属性値を書き換えることでサンタクロースの画像を出し分けています。 初期値の処理実行がないとリロードしたときにダークモードでもノーマルのサンタクロースが出てきてしまうので初期の関数実行は必要になります。

完成したページ

完成したページ

このようにデバイスがダークモードのときにだけダークサンタクロースが現れるページを作成できました。今回使用したイラストは下記のページから拝借しています。

まとめ

カラーモードでコンテンツを出し分けるページを作ってみた感想としては、はじめに述べた話題となった背景からくみ取れるように、ユーザー支援の目的として需要がある機能をコンテンツの演出として使うのは少し反抗的な制作をしたなと思いました。(それでもダークモードで見られるブラックサンタクロースを作りたい欲が勝ってしまいました。)

今回はフロントエンド視点でダークモードについて書いてきましたが、よりコンテンツを使いやすくする機能としてアクセシビリティ、UI界隈でダークモードが注目を集めているので、今後どのようにカラーモードが活用されていくのか楽しみです!