インデックスページを Light モード Dark モードに対応してリニューアルした話

Chrome 76 で prefers-color-scheme という Media Query が実装されるのに合わせ、 MasuqaT.NET のトップページ に Light モードと Dark モードの両方に対応したページにリニューアルしました。

最初から 2 モードを考慮してデザインする時に何を気にしたか・どう実装したかを手前味噌ながら載せておきます。私はデザイナさんではないので、エンジニアの趣味ページ・アプリ作成という文脈です。

prefers-color-scheme が実装された背景は prefers-color-scheme を用いた Dark Mode 対応と User Preference Media Features | blog.jxck.io が詳しいです。

リニューアル用の変更の初コミットは 5 月 19 日と、着手してから 3 ヶ月経っているので、一部分の記述は事実と異なっているかもしれません。

Light モード Light モード
Dark モード Dark モード

デザイン面

私見では、手順自体に大きな変化はなかったと思いますが、所々気にすべきところがありました。
シンプルな背景や文字の場合はモードに合った色に変えるだけで済みますが、画像等の要素をデザインとして配置する場合、色違いにしても成立するものを選ぶか、それぞれが異なる構成をモード間に矛盾なく組む必要があります。

例えば、今回のページには山と高層ビルが並べましたが、色を変えれば昼と夜でもなんとか存在感を出せるアイテムです。
暗い場所で発光しないものや光を反射しないものは当然薄黒く見えるのが通常の配色なため、特に Dark モードの場合にどう配色するか、存在感を出すかが難しかったです。
中途半端に要素を配置するよりも、シンプルな背景と文字にして(配色の本やサービスを参考に選んで)色で個性を出すのも良い手かなと思いました。

今回のページ作成を振り返ると、モード毎のテーマ決定、モード毎の色の仮決定、背景要素や文章の作成と配置、 Light モードの実装、レスポンシブ対応、 Dark モードの実装、 CI 設定という工程でした。

テーマ決定

prefers-color-scheme を活用すると決めていたため、それが目立つように Light と Dark で二元性のあるテーマにしました。
単純に、 Light は昼、 Dark は夜のテーマとし、そこに、山(当初は森)、高層ビル、太陽・月を隅に配置してモード毎に色を変えることにしました。

色を仮決定

テーマを決定したので、それに合う色を大まかにピックアップします。構成を決める前になぜ色を選ぶことから始めたかというと、 2 つのモードに対応したことによる不自然さや無理やり感を避けたく、色を優先する構成にしようと思ったからです。
例えば、配色見本の書籍とにらめっこして Light の空は黄色っぽい水色で Dark の空は紫がかった青を使おうと決めるといった具合です。

また、同時に PCCS のトーンの基準を見つつ、色毎のトーンのバランスも頭に入れておきます。

仮組み

最初にレイアウトを考えます。モードの違いが際立つよう、背景を意識させるようなものにしました。
また、今回は背景に SVG を使ったので、大体のイメージを SVG で描いて仮配置し本実装でのバランス調整に備えます。

最後に、コンテンツを作成しました。今回は文章だけだったので調整は簡単でしたが、現実世界の写真や広告が入ると苦心しそうだと強く感じました。

Light モード実装

仮組みした対象を実装していきます。prefers-color-scheme 非対応のブラウザ・バージョンの fallback として Light モードを表示するよう決めたので、 Light モードから実装を始めています。後述のように CSS Variables を使って変更箇所を切り替える仕組みにしています。
仮決定した色を元に、スペーシングやタイポグラフィを整え、さらにトーンや目立ち具合を丹念な色の調整によってイメージ通りになるよう均していきます。

全体的にまとまってきたら、 Chrome Dev Tools を開いて文字の視認性を確認します。 Light モードでは AAA 表示が出るまで文字色を濃くしています。文字色とリンク色の差がひと目ではわからなくなってしまったので、下線をつけるなどの対策を施しました。

レスポンシブ対応

デザインの順番がずれてしまった気もしていますが、スマホ・タブレット画面対応をしました。
ここの辺りはモード違いを意識せず済みました。

Dark モード実装

最後に Dark モードの実装です。こちらも大体は Light モードのときと同じです。大抵の要素は Light モードのときの CSS Variables を上書きするだけになり、それがガイドになって実装は楽でした。

一方で、背景を鮮やかにした分だけ文字の視認性を AAA にするのは至難(ほぼ #FFFFFF でないと不可)でした。少し妥協して十分と言われる AA で良しとしましたが、それでもかなり制約がありました。
視認性重視なコンテンツの場合は色を仮決めする段階から視認性を意識しておかないと、後の工程で泣きを見ることになりそうです。

技術面

今回のページはほぼデザインだったため、技術や実装という観点では、ほぼ CSS と戯れ、たまに Webpack の設定を弄る程度でした。

書く技術として CSS VariablesPostCSS を採用しましたが、当然ながら prefers-color-scheme を使います。基本的には fallback や Light モードの設定を :root 疑似セレクタ以下に、 Dark モードの設定を Media Query 以下 :root 以下に書いています。

:root { /* Light & Fallback */
--bg-color: white;
}

@media (prefers-color-scheme: dark) {
:root {
--bg-color: black;
}
}

body {
background-color: var(--bg-color);
}

また、 CSS Variables で定義した色の透明度を変えたい場合、変数を直接 #FFFFFFrgb(255, 255, 255) のようにすると CSS の機能では変換や展開できず詰むので、 255, 255, 255 のように数値だけ指定するのが回避策となっています。(または、CSS Variables を諦めて素直に PostCSS のプラグインや SCSS を使う)
rgba(#FFFFFF, 0.5)rgba(var(--bg-color), 0.5) みたいに書けるようになると表現の幅が広がって嬉しいですが、こればかりは CSS の新しいバージョンが来るまで、この変な方法で凌ぐしかないのでしょう…

:root {
--foo-bar: 255, 255, 255;
}

body {
color: rgb(var(--foo-bar));
}

p {
color: rgba(var(--foo-bar), 0.5);
}

もう一つの話題は Webpack です。本当は PostCSS のファイルを watch しておけば諸々済む話でしたが、自動リロードとか JSX ベースで書きたいので処理が要るとかの理由で、最初から設定を組んで制作していました。
後になって嬉しかったのは、SVG の最適化ができる svgo-loaderfile-loaderurl-loader をいつもの感覚で活用できたことです。
Inkscape の Optimized SVG ファイル出力ではまだ余分なデータが入っており、 svgo-loader を通すと大体 500KiB が 5KiB 未満(実際はもっと小さい)になって読込時間が減ります。また、この画像を URL encoded にして CSS に埋め込むことで、 CSS 読み込み後に生まれる通信を無くせるため待ち時間も減ります。

フォントはお馴染み Google Fonts を利用しています。タイトル文字用に、 Light モードと Dark モードで別のフォントを利用しており、現状は両方読み込むようになっているのが良くないポイントです。( “preconnect” しているので誤差程度は速いはずですが)
Lighthouse パフォーマンスはこれが原因で 99 なので、タイトル文字は SVG 化・インライン化して Web フォントを利用しない工夫をするかもしれません。

デプロイ先もお馴染み Netlify で、 ‘netlify.toml’ に yarn build して ‘dist’ を公開するよう設定しておいて、ページ用のリポジトリに Push するだけです。

感想

Light モードと Dark モード両対応のページを作ってみた感想として、疲れたという気持ちがあります。特に、モード感で矛盾無く色を調整するのが大変でした。
プロダクトの場合、両モードに対応するのはユーザーにとってちょっと嬉しいかもしれません。しかし、ビジュアルコンテンツが多い場合に、テーマカラーに基づいたパレットを複数用意してコンテンツ内の矛盾を抑えつつデザインする、というのは製作者の負担が大きそうなので、コストに見合った機能かを吟味する必要がありそうです。

また、色を調整する工程で画像の色をよく変え直す作業は楽しさがありませんでした(尤も、有料ツールなら一発かもしれませんが…)。複数モードのデザインを同時に作るという文脈で、それらをサポートするデザインルール・プロトタイピングツールは生まれてくるのでしょうか?

余談として、このブログが両モードに対応するのは時間がかかりすぎて難しそうです。既存の写真やスクリーンショットをどうするかが一番の悩みですが、例えば Dark モードならページ全体のフィルターで明度・彩度が下がる、とするだけでも案外効果があるかもしれません。