一瞬だけ、白くなる
ダークモードを入れました。色を反転させるだけの作業だと思っていたのですが、最後に厄介なものが残りました。
ページを開いた瞬間、一瞬だけ白くなる。そのあと黒に切り替わる。暗い部屋で見ると、はっきり目に刺さります。
切り替えを3状態にした理由、開いた瞬間に白くなる現象の正体、そして24か所に散らばった色を1つずつ直さずに済ませた方法です。
まず、切り替えを何状態にするか
最初は「ライト/ダーク」の2つで作りかけました。書いている途中で手が止まりました。
OSにも同じ設定があります。夜になると自動で暗くなる設定を使っている人は、サイト側で固定されると、その設定が効かなくなります。
そこで3状態にしました。
| 状態 | 何が起きるか |
|---|---|
| システムに合わせる(初期値) | OSの設定に追従する。夜に自動で暗くなる |
| ライト | OSが暗くても明るいまま |
| ダーク | OSが明るくても暗いまま |
初期値を「システムに合わせる」にしたのは、何も選んでいない人の意思表示は、すでにOS側にあるからです。サイトが勝手に上書きするものではありません。
一瞬だけ白くなる、の正体
ここが今回の本題です。
このサイトのページは、あらかじめ組み立てたHTMLを配っています。速いのですが、組み立てた時点では、見る人がどちらを選んでいるか分かりません。
選択はブラウザに保存されています。サーバーはそれを読めません。だから最初に届くHTMLは、必ずどちらかの配色で塗られた状態で届きます。
そのあとJavaScriptが動いて、保存された選択を読み、色を切り替える。この「そのあと」が見えてしまうのが、白い一瞬の正体でした。
表示が遅いページでは、白い一瞬は読み込み中の一部として紛れます。
表示が速いページでは、完成した画面が出たあとに色だけが変わるので、はっきり分かります。速くしたことが、この問題を見えやすくしていました。
解決は、順番を変えること
JavaScriptを速くしても解決しません。画面が描かれる前に決めるしかありません。
やったのは、HTMLの先頭に小さなスクリプトを1つ置くことです。ページの本体が描かれる前にブラウザがそこを読み、保存された選択(無ければOSの設定)を見て、いちばん外側の要素に印を付けます。
そのあとにCSSが適用されるので、最初から正しい色で描かれます。切り替わる瞬間そのものが無くなります。
ふだんは、描画を止めるスクリプトは避けるべきものです。表示が遅くなるからです。
ここは例外にしました。処理は数行で一瞬ですし、止めないと画面がちらつく。原則より、原則が守ろうとしているもの(見え方)を優先しました。
ついでに、スクロールバーも合わせた
色を切り替えたあとも、スクロールバーやフォームの部品が明るいままでした。これらはブラウザが描いていて、サイトのCSSでは届きません。
ブラウザに「このページは暗い配色です」と伝える指定が別にあります。それを一緒に切り替えることで、部品の側も揃いました。
色を1つずつ直すのは、やめた
ここも判断が要りました。
画面の色は「白い背景」「濃いグレーの文字」のように、部品ごとに書いてあります。素直にやるなら、その1つずつに「暗いときはこの色」を書き足していきます。
数えてみると、色の指定は24個のファイルに散らばっていました。
24か所すべてに正しく書き足せたかどうかは、全部の画面を暗くして見て回るまで分かりません。漏れた場所だけ明るいまま残ります。
しかも次に色を調整したくなったとき、また24か所を探し直すことになります。
色に名前を付けて、名前のほうを差し替えた
やり方を変えました。「白」や「濃いグレー」という色そのものではなく、その名前が指す中身を入れ替えることにしました。
部品側の書き方は一文字も変えていません。「白い背景」と書いてある場所はそのままで、「白」が何色を指すかを、明るいときと暗いときで切り替えます。
結果として、直した場所は色の定義1か所だけになりました。次に微調整したくなったときも、探すのはそこだけです。
記事の本文も、同じ仕組みで済んだ
記事の本文はCMSから来ます。見出しも段落も表も、こちらで書いたHTMLではありません。記事を書くたびに手で色を入れる運用は続きません。
ここは幸い、作ったときから色に名前を付けてありました。「本文の文字色」「罫線の色」「引用の背景」といった名前で書いてあったので、中身を差し替えるだけで済みました。当時そうしておいた理由は「あとで調整しやすいから」程度でしたが、今回はそれがそのまま効きました。
ただし、例外が2か所あった
この方法には穴があります。もともと背景が濃い場所です。
フッターとトップの見出し部分は、明るいときでも背景が濃紺です。そこに置いてある白い文字まで一緒に反転させると、濃紺の上に濃い色の文字になって読めなくなります。
この2か所だけは、名前を使わずに色を直接書きました。仕組みで揃えられる範囲と、そうでない範囲を分けた形です。
あとから見た人が「ここだけ書き方が違う」と気づいたとき、理由が書いていないと統一しようとして壊します。
直す判断のほうが自然に見えるので、なぜそうなっているかを同じ場所に残しました。
色を反転させただけでは、読めなかった
中身を入れ替えるとき、白と黒をそのまま逆にするとまぶしすぎます。
暗い背景に純白の文字を置くと、文字のふちがにじんで見えます。背景も純黒だとコントラストが強すぎて長く読めません。実際に暗い部屋で読んでみて、背景を少し明るく、文字を少し暗い白に寄せました。
逆に、薄いグレーの文字はダークモードで読めなくなります。明るいときに「補足だから薄く」としていた箇所が、暗い背景では沈んで消えます。補足の文字は、暗いとき用に明るさを上げ直しました。
明るい配色で成立していた濃淡は、暗い配色ではそのまま成立しません。
薄い=控えめ、という関係が逆になるためです。片方で作ってからもう片方を作るのではなく、両方を見ながら決める必要がありました。
やらなかったこと
画像を暗くすること。ダークモードで画像の明るさを落とす手はありますが、記事のアイキャッチはもともと暗い配色で作ってあるので、これ以上落とすと沈みます。
切り替えにアニメーションを付けること。色がなめらかに変わるのは気持ちよさそうですが、切り替えは一瞬で終わるべきものです。演出を挟むと、ちらつきを消すためにやった作業と矛盾します。
今回の学び
まず、設定は上書きより追従を初期値にすること。OSに同じ設定がある以上、何も選んでいない状態はすでに意思表示です。サイトが先に決めてしまうと、その意思が消えます。
次に、ちらつきは速さの問題ではなく順番の問題だということ。処理を速くしても、順番が後ろにある限り見えてしまいます。速くする前に、どの順で決まるかを見る必要がありました。
そして、原則には、それが守ろうとしているものがあること。「描画を止めるスクリプトを置かない」は、見え方を良くするための原則です。その原則を守ることで見え方が悪くなるなら、優先すべきは原則のほうではありません。
あわせて、散らばったものを1つずつ直さないこと。24か所に手を入れる作業は、終わったかどうかを自分で確かめられません。名前を1つ挟んで、そこだけを差し替える形に持っていけるなら、その手間のほうが安く済みます。
最後に、反転は変換ではないこと。明るい配色で作った濃淡は、暗い配色では意味が変わります。片方から機械的に作れるものだと思っていたのが、今回いちばんの見込み違いでした。
関連記事

一覧が長くなると、探せなくなる
記事の一覧に検索欄を付けました。サーバーには問い合わせず、すでに手元にある一覧をその場で絞り込みます。本文を検索の対象にしなかった理由も書いています。

見つけてもらうために、書き方は変えない
このサイトで検索まわりにやってきたことの記録。順位を上げる話ではなく、存在を知らせることと、探している人の言葉に近づけること。記事の見出しと検索結果の文字を分けた判断まで。

登録してから、広告を出すまで
成果報酬型の広告を扱えるようにした。手続き自体は難しくないが、順番を間違えると手戻りになる。準備・判断・置かない場所の決め方をまとめた記録。