KiSAKU
技術系7分で読めます

一瞬だけ、白くなる

公開

ダークモードを入れました。色を反転させるだけの作業だと思っていたのですが、最後に厄介なものが残りました。

ページを開いた瞬間、一瞬だけ白くなる。そのあと黒に切り替わる。暗い部屋で見ると、はっきり目に刺さります。

この記事で扱うこと

切り替えを3状態にした理由、開いた瞬間に白くなる現象の正体、そして24か所に散らばった色を1つずつ直さずに済ませた方法です。

まず、切り替えを何状態にするか

最初は「ライト/ダーク」の2つで作りかけました。書いている途中で手が止まりました。

OSにも同じ設定があります。夜になると自動で暗くなる設定を使っている人は、サイト側で固定されると、その設定が効かなくなります。

そこで3状態にしました。

状態 何が起きるか
システムに合わせる(初期値) OSの設定に追従する。夜に自動で暗くなる
ライト OSが暗くても明るいまま
ダーク OSが明るくても暗いまま

初期値を「システムに合わせる」にしたのは、何も選んでいない人の意思表示は、すでにOS側にあるからです。サイトが勝手に上書きするものではありません。

一瞬だけ白くなる、の正体

ここが今回の本題です。

このサイトのページは、あらかじめ組み立てたHTMLを配っています。速いのですが、組み立てた時点では、見る人がどちらを選んでいるか分かりません。

選択はブラウザに保存されています。サーバーはそれを読めません。だから最初に届くHTMLは、必ずどちらかの配色で塗られた状態で届きます。

そのあとJavaScriptが動いて、保存された選択を読み、色を切り替える。この「そのあと」が見えてしまうのが、白い一瞬の正体でした。

速いページほど、目立つ

表示が遅いページでは、白い一瞬は読み込み中の一部として紛れます。

表示が速いページでは、完成した画面が出たあとに色だけが変わるので、はっきり分かります。速くしたことが、この問題を見えやすくしていました。

解決は、順番を変えること

JavaScriptを速くしても解決しません。画面が描かれる前に決めるしかありません。

やったのは、HTMLの先頭に小さなスクリプトを1つ置くことです。ページの本体が描かれる前にブラウザがそこを読み、保存された選択(無ければOSの設定)を見て、いちばん外側の要素に印を付けます。

そのあとにCSSが適用されるので、最初から正しい色で描かれます。切り替わる瞬間そのものが無くなります。

「読み込みを止めるスクリプト」を、あえて置く

ふだんは、描画を止めるスクリプトは避けるべきものです。表示が遅くなるからです。

ここは例外にしました。処理は数行で一瞬ですし、止めないと画面がちらつく。原則より、原則が守ろうとしているもの(見え方)を優先しました。

ついでに、スクロールバーも合わせた

色を切り替えたあとも、スクロールバーやフォームの部品が明るいままでした。これらはブラウザが描いていて、サイトのCSSでは届きません。

ブラウザに「このページは暗い配色です」と伝える指定が別にあります。それを一緒に切り替えることで、部品の側も揃いました。

色を1つずつ直すのは、やめた

ここも判断が要りました。

画面の色は「白い背景」「濃いグレーの文字」のように、部品ごとに書いてあります。素直にやるなら、その1つずつに「暗いときはこの色」を書き足していきます。

数えてみると、色の指定は24個のファイルに散らばっていました。

1つずつ足すと、足し漏れが残る

24か所すべてに正しく書き足せたかどうかは、全部の画面を暗くして見て回るまで分かりません。漏れた場所だけ明るいまま残ります。

しかも次に色を調整したくなったとき、また24か所を探し直すことになります。

色に名前を付けて、名前のほうを差し替えた

やり方を変えました。「白」や「濃いグレー」という色そのものではなく、その名前が指す中身を入れ替えることにしました。

部品側の書き方は一文字も変えていません。「白い背景」と書いてある場所はそのままで、「白」が何色を指すかを、明るいときと暗いときで切り替えます。

結果として、直した場所は色の定義1か所だけになりました。次に微調整したくなったときも、探すのはそこだけです。

記事の本文も、同じ仕組みで済んだ

記事の本文はCMSから来ます。見出しも段落も表も、こちらで書いたHTMLではありません。記事を書くたびに手で色を入れる運用は続きません。

ここは幸い、作ったときから色に名前を付けてありました。「本文の文字色」「罫線の色」「引用の背景」といった名前で書いてあったので、中身を差し替えるだけで済みました。当時そうしておいた理由は「あとで調整しやすいから」程度でしたが、今回はそれがそのまま効きました。

ただし、例外が2か所あった

この方法には穴があります。もともと背景が濃い場所です。

フッターとトップの見出し部分は、明るいときでも背景が濃紺です。そこに置いてある白い文字まで一緒に反転させると、濃紺の上に濃い色の文字になって読めなくなります。

この2か所だけは、名前を使わずに色を直接書きました。仕組みで揃えられる範囲と、そうでない範囲を分けた形です。

例外は、例外だと書いておく

あとから見た人が「ここだけ書き方が違う」と気づいたとき、理由が書いていないと統一しようとして壊します。

直す判断のほうが自然に見えるので、なぜそうなっているかを同じ場所に残しました。

色を反転させただけでは、読めなかった

中身を入れ替えるとき、白と黒をそのまま逆にするとまぶしすぎます。

暗い背景に純白の文字を置くと、文字のふちがにじんで見えます。背景も純黒だとコントラストが強すぎて長く読めません。実際に暗い部屋で読んでみて、背景を少し明るく、文字を少し暗い白に寄せました。

逆に、薄いグレーの文字はダークモードで読めなくなります。明るいときに「補足だから薄く」としていた箇所が、暗い背景では沈んで消えます。補足の文字は、暗いとき用に明るさを上げ直しました。

反転は、変換ではない

明るい配色で成立していた濃淡は、暗い配色ではそのまま成立しません。

薄い=控えめ、という関係が逆になるためです。片方で作ってからもう片方を作るのではなく、両方を見ながら決める必要がありました。

やらなかったこと

画像を暗くすること。ダークモードで画像の明るさを落とす手はありますが、記事のアイキャッチはもともと暗い配色で作ってあるので、これ以上落とすと沈みます。

切り替えにアニメーションを付けること。色がなめらかに変わるのは気持ちよさそうですが、切り替えは一瞬で終わるべきものです。演出を挟むと、ちらつきを消すためにやった作業と矛盾します。

今回の学び

まず、設定は上書きより追従を初期値にすること。OSに同じ設定がある以上、何も選んでいない状態はすでに意思表示です。サイトが先に決めてしまうと、その意思が消えます。

次に、ちらつきは速さの問題ではなく順番の問題だということ。処理を速くしても、順番が後ろにある限り見えてしまいます。速くする前に、どの順で決まるかを見る必要がありました。

そして、原則には、それが守ろうとしているものがあること。「描画を止めるスクリプトを置かない」は、見え方を良くするための原則です。その原則を守ることで見え方が悪くなるなら、優先すべきは原則のほうではありません。

あわせて、散らばったものを1つずつ直さないこと。24か所に手を入れる作業は、終わったかどうかを自分で確かめられません。名前を1つ挟んで、そこだけを差し替える形に持っていけるなら、その手間のほうが安く済みます。

最後に、反転は変換ではないこと。明るい配色で作った濃淡は、暗い配色では意味が変わります。片方から機械的に作れるものだと思っていたのが、今回いちばんの見込み違いでした。

← ブログ一覧へ戻る