Day 9: ダークモード用のボタンの配色デザインを理詰めで決める
要約(TL;DR)
Google マップを埋め込む web アプリを制作するにあたり、ダークモード用のボタンの配色デザインをした。なるべく、ライトモード用の配色と同じ理屈で色を選ぶようにした。UI に一貫性を持たせるために。
しかし、ダークモードに特有の理屈が幾つかあることを、配色デザインをする過程で学んだ。
一つは、ライトモードと同じような半透明さを実現するには、カラーコード上での不透明度(opacity)をより低く設定する必要があること(第2節参照)。
もう一つは、発光しているように見せるための「影」の設定において、ダークモードでは、blur radius をより長く指定しないと自然に見えないこと(第6節参照)。
はじめに
My Ideal Map App という、Googleマップの使い勝手(user experience)を改善する web アプリを制作している(詳しくは、過去記事 Day 1 を参照)。
メインとなる UI 画面は、画面いっぱいに Google マップを埋め込み、画面の隅に主要な機能を実行するためのボタンを地図の上に重ねて配置する。
このボタンのデザイン・及び実装について、過去記事 Day 7 と Day 8 で詳しく書いてきた。
当記事は、その続編。ボタンのダークモード用の配色をどう決めていくか、について。
なお、この記事では、ダークモードの対語として「ライトモード」という言葉を使う(英語では "light mode" が "dark mode" の対語として一般的)。省電力モードという意味での「ライトモード」ではない。
1. ライトモードとの一貫性
ダークモード用の配色デザインは、ライトモードとの一貫性がないと、ユーザーに別のアプリだと思われてしまいかねない。
一貫性を持たせる方法は、一つ一つの色を選ぶ理由を可能な限り同じにすることだと思う。
My Ideal Map App のライトモードでは、ボタンの配色は以下のようになっている。
ライトモードでのボタンの配色(筆者作成)
キーボード・ユーザーがボタンをフォーカスした時、及び、マウス・ユーザーがボタンの上にカーソルを置いた時、配色は以下のように変わる。
ライトモードでのボタンがフォーカスされた時の配色(筆者作成)
それぞれの色には、選んだ理由がきちんとある(過去記事 Day 7 を参照)。その理由を参考にしながら、ダークモードでの配色を決めていった。
2. 塗りつぶしの色(fill color)
ライトモードでは、ボタンの塗りつぶしの色は、透明度7%の純白( rgba(255, 255, 255, 0.93))にした。その理由は、
雲は白い。そして、半透明にすることで、その下の地図をうっすらを見せることで、地図の上に雲が浮かんでいるという印象を与える。透明度7%という値は、ボタンとして認識されるかどうか(透明すぎるとボタンではなくなる)、及び、浮かんでいるように見えるかどうか、という二つの要件のバランスがちょうどいい値として選んだ。(過去記事 Day 7 より引用)
ダークモードでは、ボタンの色を白にしてしまうと、画面の大部分を占める地図の配色が暗いため、眩しくなってしまう。これを避けるため、ボタンの色は、地図上で最も明るい色と同程度の明度の灰色にする。地図上で最も明るい色は、道路の色として使っている暗めのオレンジ。
My Ideal Map App のダークモード配色で、Webページに埋め込んだ Google マップ(筆者によるスクリーンショット)
このスクリーンショットを見てわかるように、白いボタンは、この地図の配色の中では眩しい。
道路の場所を示す暗めのオレンジ(#ae6f2f)と明度が同じぐらいのグレーは、rgb(123, 123, 123)。この色をボタンの塗りつぶしの色に選んだ。こうすれば、ボタンが眩しいということはない。
rgb(123, 123, 123) と #ae6f2f の明度比 (画像元: contrast-ratio.com)
そして、地図という空から見下ろした街の様子の上に浮かぶ雲としてのボタンのイメージに合うように、ボタンを半透明にしたい。かといって、透明にしすぎるとボタンとして認識してもらえなくなるので、そのバランスがちょうど良い透明度を探した結果、20%がベストだった(つまり、rgba(123, 123, 123, 0.8) )。
ライトモードでは、透明度7%がベストだった。全体が暗くなると、透明感を出すのに最低限必要な透明度は高くなるようだ。
3. 輪郭線の色 (outline color)
ボタンの輪郭線の色は、ライトモードでは rgb(148, 148, 148) にした。その理由は、
雲の白色と、地図中の道路の白色が区別できるようにするため。地図の配色には、道路の純白 (#ffffff) から市街地のグレー (#898989) までの明度差がある。雲の半透明の白は、このグレーを背景にしたとき、明度差が十分にあるので、雲と市街地が重なっても、雲ボタンをはっきり認識できる。しかし、白い道路を背景にすると、当然区別がつかなくなる。明度比が 3:1 を満たすようなグレーを選んだ(過去記事 Day 7 からの引用)
ダークモードでも、ボタンの塗りつぶしの色と道路の色の明度が同程度なので、同様の考慮が必要になる。
そこで、ボタンの輪郭線の色を、#2b2b2b にする。この色は、地図上で最も明度の低い色である市街地(道路で囲まれたエリアのこと)の色と同じ。市街地と道路は隣接するので、道路がはっきり認識できるように、明度差が3倍以上になるように設定していた(過去記事 Day 5 を参照)。
こうすることで、ボタンが道路の上に表示された場合は、道路よりも十分に暗い輪郭線によってボタンが認識できる。また、ボタンが市街地の上に表示された時は、輪郭線が市街地と一体化し見えなくなる。必要なときにだけ、輪郭線が見えるようにした。
4. 影の色
ライトモードでは、ボタンの影の色を透明度67%の黒(rgba(0, 0, 0, 0.33))とした。その理由は、
こうすることで、輪郭線と影の境目を曖昧にし、ボタンの輪郭線を影の一部として認識させることが可能になる。(過去記事 Day 7 からの引用)
ダークモードでも、輪郭線と影の境目を曖昧にしたい。道路の色であるダークオレンジ(#ae6f2f)を背景色とした時の明度比が、輪郭線のグレー(#2b2b2b)の明度比と近くなるように、黒の透明度を調整したところ、透明度 35% (つまり、rgba(0, 0, 0, 0.65))となった。
rgba(0, 0, 0, 0.65) と #ae6f2f の明度比 (画像元: contrast-ratio.com)
#2b2b2b と #ae6f2f の明度比 (画像元: contrast-ratio.com)
しかし、この半透明の黒をそのまま影の色に使っても、ボタンの輪郭線と同じような色にはならない。影の濃さが、ボタンから離れるほど緩やかに薄くなっていくように、blur-radius が異なる影を三重に重ねる必要があるから(詳しくは、過去記事 Day 7 第7節、及び、Ahlin (2019) を参照)。
三重に重ねた半透明の黒が、透明度35%となるようにするには、それぞれの黒が透明度70%にする必要がある(0.7 の三乗は、約0.35)。影をボタンの真下に作る場合(つまり、offset の値が x 方向にも y 方向にも 0 の時)、影の色の不透明度 (opacity) はボタンの端において半減することを考慮すると、透明度 40% (不透明度 60%) の黒をボタンの影の色にすると、ボタンの端で透明度が 70% (不透明度 30%) になる。
したがって、影を CSS で以下のように設定すればいい。
filter:
drop-shadow(0px 0px 1px rgba(0,0,0,0.6))
drop-shadow(0px 0px 2px rgba(0,0,0,0.6))
drop-shadow(0px 0px 4px rgba(0,0,0,0.6));
ボタンは、SVG画像なので、box-shadow プロパティーではなく、filter プロパティーの drop-shadow 関数を用いている(Olawanle 2021 を参照)。
5. ラベルの色
ダークモードでのボタンのラベルの色については、ライトモードとは異なる理屈が必要になる。ライトモードでは、ボタンの塗りつぶしの色(つまり、ラベルの背景色)を純白にしたので、ラベルを認識するのに十分な明度差のある色は、幾らでもある。他方、ダークモードでは、ラベルの背景色は上記の通りグレー。より明るいグレーのうち、十分な明度差を確保できるものは多くない。選択肢がすでに限られている。
ボタンの塗りつぶしの色である rgb(123, 123, 123) との明度差がギリギリ 3:1 になるようなグレーは、rgb(218, 218, 218) だった。
rgb(218, 218, 218) と rgb(123, 123, 123) の明度比 (画像元: contrast-ratio.com)
* * *
ここまでの配色をまとめると、以下のようになる。
ダークモードでのボタンの配色(筆者作成)
6. フォーカス及びホバー・ステートの配色
ライトモードでは、フォーカス・ステート(キーボード・ユーザーがボタンにフォーカスした時)及びホバー・ステート(マウス・ユーザーがボタンの上にカーソルを置いた時)の配色として、輪郭線及び影の色に水色(rgb(69, 159, 189))を用いて、ボタンの周りが光るようにした。この水色は、白との明度差が 1:3 を満たしているので、地図上の白い道路の上に重なった時でも認識できる。
ダークモードでは、フォーカス及びホバーされた時にボタンが月の光に照らされるようにしたい。シンプルに純白を用いて、月の光を以下の CSS コードで表現した。
button:focus #cloud,
button:hover #cloud {
stroke: rgba(255,255,255,0.4);
}
button:focus svg,
button:hover svg {
filter: drop-shadow(0 0 10px rgb(255,255,255));
}
ボタンの形は、SVG 画像の <path id="#cloud"> 要素を用いて描いているので、輪郭線の色を指定するのに(border ではなく) stroke プロパティーを使っている。
影の色は、透明度ゼロの純白(rgb(255, 255, 255))を用いているが、輪郭線には、透明度60%の純白(rgba(255, 255, 255, 0.4))を用いた。そうしないと、輪郭線が目立ってしまう。
また、影の blur radius は 10px にした。これはライトモードで用いた 5px よりも大きい。こうしないと、光を反射しているように見えない。おそらく、暗い中では光が遠くまで届くように見えるからだろう。
ボタンのラベルの色も、月の光に合わせて、純白にする。
button:focus svg,
button:hover svg {
fill: rgb(255, 255, 255);
}
color ではなく fill プロパティーを用いているのは、ボタンのラベルにテキストではなく SVG アイコンを用いているから。
以上をまとめると、フォーカス・ステートの配色は以下のようになる。
ダークモードでのボタンがフォーカスされた時の配色(筆者作成)
純白は少し眩しいかもしれない。ライトモードのフォーカス・ステートは、後日考え直さないといけないことがある(過去記事 Day 7 第8節参照)ので、その時に同時に「月の光」の色を再考することにする。
7. アクティブ・ステート
ライトモードでは、ユーザーがボタンを押した瞬間に一時的に影と輪郭線を消すことで、ボタンが点滅するように見せて、ユーザーが「ボタンを押した」という感覚を持てるようにした。
ダークモードでも同様にする。すなわち、CSSコードを
button:active #cloud {
stroke: none;
}
button:active svg {
filter: none;
}
とした。
次のステップ
以上の設定により、ダークモードでは My Ideal Map App は以下のように表示されるはずである。
My Ideal Map App のダークモード UI (筆者によるスクリーンショット)
このダークモードUIを実装するための CSS 及び JavaScript コードは簡単に書ける、と思っていた。CSS variables を属性セレクターと組み合わせ、ダークモードに切り替える時に属性を変更させればいいだけ (Adhuham 2020 及び Dodds 2020 を参照)。
しかし、世の中甘くない。思わぬ落とし穴が待ち構えていることにこの時点では気づかなかった。。。
(次回に続く)
注: この記事は、英語で書いた同内容の記事を和訳すると同時に日本人向けに編集したものです。
引用文献
Adhuham (2020) “A Complete Guide to Dark Mode on the Web”, CSS-Tricks, Jul 1, 2020.
Ahlin, Tobias (2019) “Smoother & sharper shadows with layered box-shadows”, tobiasahlin.com, Sep 19, 2019.
Dodds, Kent C. (2020) “Use CSS Variables instead of React Context”, Epic React, Oct 2020.
Olawanle, Joel (2021) “Adding Shadows to SVG Icons With CSS and SVG Filters”, CSS-Tricks, Jun 11, 2021.
この記事が気に入ったらサポートをしてみませんか?