echo "hello, darkness" ~Webサービスにおけるダークモードという闇~

**[闇の魔術に対する防衛術 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yaminomajutu)** の11日目の記事です(当日参加登録)。

現在、明日(12日目)も、明後日(13日目)もエントリーはありません。
**あなたの抱えている闇を記事にしてみませんか？**

---

# echo "hello, darkness"

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">echo &quot;hello, darkness&quot; <a href="https://twitter.com/hashtag/GitHubUniverse?src=hash&amp;ref_src=twsrc%5Etfw">#GitHubUniverse</a> <a href="https://twitter.com/hashtag/Keynote?src=hash&amp;ref_src=twsrc%5Etfw">#Keynote</a> <a href="https://t.co/9gQRFt3aqQ">https://t.co/9gQRFt3aqQ</a> <a href="https://t.co/HEotvXVJ7R">pic.twitter.com/HEotvXVJ7R</a></p>&mdash; GitHub (@github) <a href="https://twitter.com/github/status/1336362679506784256?ref_src=twsrc%5Etfw">December 8, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

2020/12/8 GitHubが **Webサービスにおいて、ダークモードに対応するということは、闇に堕ちなければいけない** ~~フォースのダークサイドが実現させた世界~~ ということを表す動画を作成しました。(違う)

本記事では、Webサービスをダークモード対応させるときに、堕ちなければならない闇について記載します。

⚠️ 歴史や現在の状況について調査不足で誤りがあるかもしれません。誤りがあれば、コメント等で指摘いただけると助かります。

# そもそもダークモードって

ダークモードで調べてもWikipedia の日本語記事はありません。現在、ダークモードという単語は、特に開発者にとって、難しい単語となっているように感じます。

**ダークモードは、一般的にはカラーテーマ** として用いられることが多いでしょう。**「ダークテーマ」や「ナイトモード」などと区別せずに使われることが多い** と感じます。

ただし、**2019年に、iOSやandroidがOSのネイティブな機能としてダークモードを搭載することを発表した** ことで、開発者にとってはカラーテーマに限定した単語ではなくなりました。
ダークモードという言葉に、 **システム(OS)に設定したカラーテーマ、ならびに、それに対応したアプリケーションのカラーテーマ** が含まれるようになったのです。

**ダークモードに対応した、iOSやandroidのアプリケーションを作るときの考え方は比較的簡単** でしょう。色を指定する時には、**なるべく定義済みのダイナミックシステムカラーを使い**、必要に応じて、**カスタムのセマンティックカラーを定義して使用** すればよいのです。そのように作成しておけば、OSに設定したカラーテーマに従って、適切なカラーが使用されるでしょう。(参考: **[iOS 13からのダークモード対応のコツ - Qiita](https://qiita.com/gonsee/items/c04b73787730c0e831df)**)

一方で、Webサービス、つまり、Webサービスの実行環境であるブラウザにおける対応は、上記とは異なります。現在、**ブラウザではブラウザ自体にカラーテーマを設定する機能はありません**。そのため、 **システムに設定したカラーテーマに応じて色が変わるセマンティックカラーを標準機能で定義することはできない** のです。

ブラウザ自体にカラーテーマを設定する機能がない代わりに、 **[`prefers-color-scheme`](https://developer.mozilla.org/ja/docs/Web/CSS/@media/prefers-color-scheme)** が使用できます。**`prefers-color-scheme` はcssのメディアクエリ** です。

繰り返しますが、**`prefers-color-scheme` はCSSのメディアクエリ** です。ブラウザの機能の１つであるCSSに含まれる機能です。これが、Webサービスの開発にどのような闇をもたらしているのかを見てみましょう。


# Webサービスのダークモードの闇

## ダブルスタンダードを強いられる

そもそも、OSレベルのダークモードと、Webサービスのダークモードは、今までの利用者の認識も大きく異なります。
**OSレベルでのダークモードは、今まで実現されていなかった領域** の一方で、 **Webサービスでのダークモード(テーマ切替)は比較的馴染みのあるもの** でしょう。そのため、**OSのカラーテーマと、Webサービスのカラーテーマが異なる事に違和感は感じない** でしょう。

そのような背景の中で、OSレベルでテーマを選択できるようになりました。 **Webサービスにおいて、常にOSとテーマを合わせるというのは、ユーザにとって不便さを感じさせることもある** でしょう。例えばOSのテーマが今まで通りlightであったとして、Webサービスだけdarkのテーマを使いたいというニーズが必ずあります。つまり、 **Webサービスにおいては、OSレベルの選択されたテーマを考慮しつつ、テーマを選択できるようことが求められる** ようになったのです。

WebサービスでOSレベルのテーマと連携するためのインターフェースは `prefers-color-scheme` です。 **`prefers-color-scheme` はcssのメディアクエリであるため、OSレベルの選択されたテーマを知ることしかできません** 。 **CSSの機能では状態を保存しておくことができない** ため、テーマを選択できるようにした場合は、 **その選択状態を保存しておくための別の仕組みが必要** になるのです！

もし、`prefers-color-scheme` ではなく、ブラウザ側の機能で、お気に入りやPWAのように、サイト毎にテーマを保存し、それを参照できるような仕組みがあれば、今までよりもテーマを切り替えるための開発は容易になったでしょう。しかし、そうではありません。

つまり、**OSに搭載されたダークモードの機能、並びに `prefers-color-scheme` は、Webサービスにおけるダークモード対応を容易にするものではなく、むしろ、ダブルスタンダードを推奨し、開発を複雑にするもの** なのです。


## 画像やSVGに対する闇

**あなたは、画像をCSSで表示していますか？**

iOSの **[Dark Mode - Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode)** に以下の記載があります。

> 必要に応じて、明るい外観と暗い外観の個々のグリフを設計します。ライトモードで中空のアウトラインを使用するグリフは、ダークモードでは塗りつぶされた塗りつぶされた形状として見栄えがよくなります。

> フルカラーの画像とアイコンが見栄えがよいことを確認してください。ライトモードとダークモードの両方で見栄えがよい場合は、同じアセットを使用します。アセットが1つのモードでのみ良好に見える場合は、アセットを変更するか、明るいアセットと暗いアセットを別々に作成します。アセットカタログを使用して、アセットを1つの名前付き画像に結合します。

つまり、**アイコンや画像の見栄えは通常時とダークモード時の両方で確認し、必要に応じて切りかえる必要がある** ということです。iOSでは、アセットカタログを使用することで、画像を使用する側は明示的に切り替える必要はありません。

さて、 **これを `prefers-color-scheme` で実現する** にはどうすればいいでしょうか？

１つは対象の画像をCSSで表示させることです。ただし、アイコンや画像はimgタグだけとは限りません。svgを使っている場合はどうでしょうか。

これらを動的に切り替えるには、JavaScriptで `prefers-color-scheme` に相当する判定が必要でしょう。これは `window.matchMedia`[^1] を使用することで確認できます。(参考: [CSS/JavaScriptでダークテーマに対応する方法 (2019/9更新)](https://qiita.com/unipota/items/ec552bd3d782844e65ef))

[^1]: https://developer.mozilla.org/ja/docs/Web/API/Window/matchMedia

``` js
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  /* ダークテーマの時 */
} else {
  /* ライトテーマの時 */
}
```

もちろん、これは判定のみです。Webを開いてるときに、OSのテーマを変えられた時を考慮して、切替イベントも拾うほうがよいでしょう。~~ほんとにいるのか？~~

ダークモードの切替による修正はレイアウトの問題であるので、CSSで記載したいという気持ちもわかりますが、**現実問題としてCSSのみで対応ができないケース** も出てくるのです。

## `mix-blend-mode`を使用したdarkmode.jsという闇

「darkmode js」でググると、**[Darkmode.js](https://darkmodejs.learn.uno/)** というライブラリを知ることになるでしょう。

**[あなたのWEBサイトを爆速でダークモードにする(Darkmode.js) - Qiita](https://qiita.com/yoshi_yast/items/afe81ce27f38119dbcdd)** にも紹介されている通り、まさに **爆速** でダークモードにできる素晴らしいライブラリです。

しかし、darkmode.jsには、闇の魔術が使われています。darkmode.jsは、`mix-blend-mode`[^2] の `difference` を使って画面全体の色を反転させます。オプションやクラスの指定で、特定の要素を反転させないこともできます。

[^2]: https://developer.mozilla.org/ja/docs/Web/CSS/mix-blend-mode

画像やsvgも含めて反転できる、 **コロンブスの卵な発想のライブラリ** ですが、`mix-blend-mode` の本来の使用方法を考えると、やはり闇の魔術という感じがします。

そのため、例えば **色相を変えずに、彩度だけ反転させれるようなオプションがあればいいのに** と思うのですが、そのような闇の魔術は発見されていないのです。


## フレームワークの闇

結局はダークモードはカラーテーマの話であり、 **カラーテーマにはCSSフレームワークを使用していることも多い** でしょう。本来であればダークモードについては、CSSフレームワークの問題領域といっても過言ではないかも知れません。

使用しているCSSフレームワークが、バージョンを上げるだけでダークモード対応されたら歓喜の渦に包まれるでしょう。

しかし、 **現状の有名なフレームワークは、個別にダークモード用のクラスを指定するなどの対応を行う必要がある** ものがほとんどです。これは、OSにダークモードが搭載されると決まったのが比較的最近であることに加え、 `prefers-color-scheme` というCSSのメディアクエリというインターフェースが、使い勝手の良いCSSフレームワークを作りにくくしているという点もあるでしょう。


## プラグインの闇

ブラウザのプラグインにおけるダークテーマを利用してきたユーザも多いでしょう。プラグインにはインストール等の制約も付きますが、ダークモードを求めていたユーザは、プラグインで十分にニーズを満たせていた、ということはないでしょうか？


# Webサービスはダークモード対応しない方がいいの？

ここまで闇を紹介しましたが、本来テーマ変更はWebサービスでよく行われてきた手法でもあります。Webサービスのダークモード対応自体が全て闇ではなく、 **テーマ変更を考えていなかったサイトのダークテーマ対応には、時として闇に堕ちなければならないほどの苦悩が発生する** という事が本記事の主旨です。

当初からダークモードへのテーマ変更を想定したWebサービスであれば、ダークモードに対するプラクティスはあるでしょう。

 - 色については、SCSSの変数を使用すること
 - 切替方式を設計すること
 - 画像やsvgの使用に注意すること
 - デフォルトのテーマ決定は `prefers-color-scheme` を使用すること

あたりでしょうか。


# 参考

**[Light-on-dark color scheme - Wikipedia](https://en.wikipedia.org/wiki/Light-on-dark_color_scheme)**

# あとがき

いかがでしたか？

冒頭の動画に、GitHubがダークモードに対応するための **闇に堕ちるほどの苦悩が表現されている** ことが理解していただけたでしょう。（違う）
`echo "hello, darkness"` というツイートからわかる様に、 **GitHubはダークモード対応で初めて闇の技術を使ってしまった** そうです。(違う)

本記事を、 **ダークモードに対応していないWebサービスを馬鹿にする人たちへの闇の魔術** として利用していただけたら幸いです。

---

**[1日目](https://qiita.com/j5c8k6m8/items/0f0596845b63e3b32d7d)**, **[2日目](https://qiita.com/j5c8k6m8/items/009da491fad911834c3b)**, **[4日目](https://qiita.com/j5c8k6m8/items/dffa2bcc55985ec8ecca)** **[7日目](https://qiita.com/j5c8k6m8/items/64d09fc5d68c79a15cf9)** と続き、5記事目となってしまいました。

そういえば、今年はCSSのアドベントカレンダーが無いですね。