タグ: UI設計

  • 一瞬だけ、白くなる

    一瞬だけ、白くなる

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

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

    この記事で扱うこと

    切り替えを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つ挟んで、そこだけを差し替える形に持っていけるなら、その手間のほうが安く済みます。

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

  • 一覧が長くなると、探せなくなる

    一覧が長くなると、探せなくなる

    記事の一覧ページに検索欄を付けました。作りながら決めたことを書いておきます。

    結論から書くと、サーバーには問い合わせていません。検索という言葉から想像される仕組みより、だいぶ簡単なものを選びました。なぜそれで足りると判断したかが、この記事の中身です。

    この記事で扱うこと

    検索をサーバー側でやらないと決めた理由、検索の対象に本文を入れなかった理由、そして表記ゆれの吸収です。

    そもそも、なぜ必要になったのか

    記事が20本を超えたあたりで、自分でも過去記事を探せなくなりました。

    「DNSの話、どの記事に書いたっけ」と思って一覧を開き、上から順に見出しを読んでいく。これは読者にやらせる作業ではありません。

    用語集には先に検索を付けていました。116語を目で追うのは無理だと分かっていたからです。記事も同じ状態になりつつありました。

    サーバーに聞かない、と決めた

    検索の作り方は大きく2つあります。

    やり方 仕組み
    サーバー側 入力のたびにCMSへ問い合わせ、絞り込んだ結果を返してもらう
    ブラウザ側 すでに読み込んである一覧を、その場で絞り込む

    WordPressには検索の仕組みが最初から入っていて、GraphQLからも呼べます。素直に考えればそちらです。

    それでもブラウザ側にしたのは、一覧ページがすでに全記事を持っていたからです。

    このサイトの一覧ページは、あらかじめ組み立てたHTMLを配っています。ページを開いた時点で、全記事のタイトル・抜粋・タグはもうブラウザの中にあります。そこにあるものを、わざわざもう一度サーバーに聞きに行く理由がありません。

    聞きに行くと、壊れやすくなる

    入力のたびにCMSへ問い合わせると、CMSが落ちている間は検索も落ちます。

    いまの構成は、CMSが止まっていても閲覧は続けられるようにしてあります。検索のためにその性質を手放すのは、割に合いませんでした。

    もちろん、これは記事数に依存する判断です。数百本になれば一覧ページ自体が重くなるので、そのときは作り直します。いま正しいことと、ずっと正しいことは違います。

    本文は、検索の対象にしなかった

    次に迷ったのが、どこまでを検索の対象にするかです。

    本文まで探せたほうが便利なのは間違いありません。ただ、一覧ページは本文を読み込んでいません。タイトルと抜粋とタグだけです。

    本文まで含めると、一覧ページが運ぶデータは数十倍になります。検索できるようにするために、一覧ページの表示が遅くなる。これは順序が逆だと思いました。

    検索欄を使う人より、一覧をそのまま眺める人のほうが多いはずです。多いほうを遅くして、少ないほうを便利にする交換はしたくありませんでした。

    「便利」は、どこかの負担と交換されている

    機能を足すとき、増えるのは画面の要素だけではありません。読み込む量、壊れる箇所、直す手間も一緒に増えます。

    足す前に「何と引き換えか」を書き出すと、要らない機能はだいたいそこで消えます。

    表記ゆれを、どこまで吸収するか

    日本語の検索でいちばん厄介なのは、同じものを指す書き方が複数あることです。

    同じ記事にたどり着いてほしい入力
    Next.js
    next.js
    nextjs
    NEXT
    ネクスト

    全部を完璧に扱うのは無理なので、機械的に処理できる範囲だけ揃えました。

    やっているのは4つです。全角と半角を揃える、大文字と小文字を揃える、カタカナをひらがなに寄せる、記号と空白を落とす。入力側と、記事側の両方に同じ処理をかけてから比べます。

    これで「WordPress」も「wordpress」も「ワードプレス」も同じ扱いになります。「ネクスト」で Next.js が出るところまでは面倒を見ていません。そこまでやるなら辞書が必要で、辞書は誰かが更新し続けないと古びます。

    用語集と同じ関数を使った

    この処理は、用語集の検索ですでに書いてありました。

    そのままコピーすることもできましたが、コピーした側は直されません。片方の揺れを直したときに、もう片方は古いままになります。共通の場所に出して、両方から呼ぶようにしました。

    関数を1つ切り出すだけの作業ですが、2箇所目が現れた時点でやっておかないと、3箇所目が現れたときにはもう誰も揃えません。

    0件のときに、何を出すか

    最後まで残ったのがこれでした。

    「見つかりませんでした」とだけ出すのは、行き止まりです。探しに来た人を、何も持たせずに帰らせることになります。

    このサイトには用語集があります。記事名では見つからなくても、語の説明としては存在していることが十分あり得ます。0件のときは、その語で用語集を引く導線を出すようにしました。

    行き止まりを作らない

    0件は失敗ではなく、「その言葉では記事が無い」と分かった状態です。次に行ける場所を1つ添えるだけで、意味が変わります。

    今回の学び

    まず、すでに手元にあるものを数えること。検索と聞くと問い合わせる仕組みを想像しますが、一覧ページはもう全記事を持っていました。持っているものを使えば、増える部品はゼロです。

    次に、機能を足すときは何と引き換えかを書くこと。本文まで検索できるようにすると、一覧の表示が遅くなります。多いほうを犠牲にして少ないほうを便利にしていないか、毎回確かめる価値があります。

    そして、同じ処理が2箇所目に現れたら、その時点で1つにすること。コピーした側は直されません。3箇所目が現れてからでは遅すぎます。

    最後に、0件にも行き先を用意すること。見つからなかったという事実は、それ自体が次の手がかりになります。

  • 見つけてもらうために、書き方は変えない

    見つけてもらうために、書き方は変えない

    このサイトで検索まわりにやってきたことを、順番に並べてみます。

    先に立場を書いておくと、順位を上げる方法は扱いません。やってきたのは「存在を知らせる」「探している人の言葉に近づける」の2つだけで、どちらも順位を操作する話ではありません。

    この記事で扱うこと

    何を先にやったかという順番、記事の見出しと検索結果の文字を分けた判断、そして「やらないと決めたこと」です。

    最初にやったのは、存在を知らせること

    公開したばかりのサイトには、外部からのリンクがありません。検索エンジンはリンクをたどってページを見つけるので、誰からもリンクされていないサイトは、そもそも見つけてもらえません。

    そこで最初に用意したのは3つです。

    用意したもの 役割
    sitemap.xml ページの一覧を直接渡す
    robots.txt 見に来てよい範囲を伝える
    構造化データ ページの意味を機械が読める形で示す

    あわせてSearch Consoleに登録しました。ここでつまずいた話は別記事にしていますが、要点はドメインを買った会社の管理画面と、実際にDNSを答えているサーバーが別だったことです。設定は保存できるのに、誰も参照しない。エラーも出ない。丸一日かかりました。

    順位ではなく、到達

    これらは順位を上げるものではありません。見つかるまでの時間を短くするものです。

    存在を知られていない状態で書き方の工夫をしても、読む相手がいません。順番として、先にこちらでした。

    次にやったのは、記事どうしをつなぐこと

    記事が20本を超えたあたりで、1本読んだ人が次に何を読むかという導線が無いことに気づきました。

    やったことは3つです。

    ひとつめは用語集です。116語をまとめ、記事の末尾から「この記事に出てくる用語」として繋ぎました。これは検索対策として始めたものではなく、初学者にも読めるようにするためのものです。ただ結果として、記事どうしが用語を介してつながりました。

    ふたつめは関連記事です。以前は「1つ新しい記事」と「1つ古い記事」しか出していませんでしたが、公開日が近いことと内容が近いことには関係がありません。タグの重なりで選ぶように変えました。

    みっつめはページの統合です。実績とスキルの個別ページは、トップページの同名セクションとほぼ同じ内容でした。同じ内容が2つのURLにあると、検索エンジンにどちらを出すか選ばせることになります。統合して、旧URLは転送しました。

    そして、タイトルを2つに分けた

    ここが今回いちばん考えた部分です。

    このサイトの記事の見出しは、内容を説明するのではなく、含みを持たせて付けています。

    これまでの見出し
    速くしたら、壊れた
    所有権をどう証明するか
    「読み終えた」をどう数えるか
    ゆっくり読む人ほど、読了にならなかった

    読んだあとに何かが残るように、と思って付けています。

    ところが検索する人は、この言葉では探しません。「所有権をどう証明するか」で検索する人はいませんが、「Search Console 所有権確認 DNS」で困っている人はいます。中身はまさにそれなのに、言葉が噛み合っていませんでした。

    見出しを書き換える案は、やめた

    検索語を入れた説明的な見出しに直せば、噛み合います。しかしそれをすると、読み物としての性格が変わります。

    このサイトは、作業の記録であると同時に、判断の記録として書いています。見出しはその入口なので、そこを検索エンジンに合わせて書き換えるのは、目的と手段が入れ替わっている気がしました。

    場所によって、見られ方が違う

    検索結果のリンクは「探している言葉と一致するか」で開かれます。SNSで共有されたリンクは「面白そうか」で開かれます。

    見られ方が違うなら、出す文字も違っていい。そう整理したら、答えが出ました。

    見出しはそのままにして、検索結果に出す文字だけを別に持つことにしました。SNSで共有されたときは見出しのほうを出します。

    出る場所 出す文字
    検索結果 Search Consoleの所有権確認をDNSのTXTレコードで行う
    ページの見出し・SNS 所有権をどう証明するか

    文字数も測った

    あわせて、検索結果に出る幅も測りました。目安は全角30文字ほどです。

    サイト名の接尾辞「| KiSAKU Portfolio」が全角9.5文字ぶんを毎回占めていて、公開中21本のうち14本がこの幅を超えていました。接尾辞を記事ページから外すだけで、超えるのは7本に減りました。

    サイト名は検索結果のURL表示にも出ています。タイトルの中で場所を取ってまで繰り返す必要は、薄いと判断しました。

    やらないと決めたこと

    逆に、やらないことも決めました。

    検索語を狙って記事を量産すること。書いていないことは書けません。このサイトの記事は、実際に自分がつまずいて調べたことだけで成り立っています。検索語から逆算して書き始めると、その前提が崩れます。

    用語を1語1ページにすること。個別ページのほうが検索に有利、という一般論はあります。しかし1語400字のページを100枚作ると、中身の薄いページが多いサイトと見なされる可能性がありました。この規模では逆効果と判断して、分野ごとにまとめています。

    広告を置ける場所すべてに置くこと。内容と無関係な記事に広告を挟むと、読んだ人の信頼を削ります。掲載できる場所の数と、掲載すべき場所の数は違います。

    一般論が、自分の規模で成立するとは限らない

    「個別ページのほうが強い」「記事数が多いほうが有利」——どれも間違いではありませんが、条件付きの正解です。

    条件を確かめずに無条件の正解として受け取ると、規模が合わないまま実行して逆効果になります。

    まだ測っていない

    正直に書くと、ここまでの効果はまだ数字で確かめていません。

    Search Consoleに登録したのが最近で、記事の公開も始めたばかりです。いま順位やクリック数を見ても、変化なのか誤差なのか区別がつきません。

    やったことを記録しておいて、数字が溜まってから振り返るつもりです。効果を確かめる前に「効果があった」と書かないことも、この記録の一部だと思っています。

    今回の学び

    まず、順番があること。存在を知られていない段階で書き方を工夫しても、読む相手がいません。まず見つかる状態を作り、それから中身の噛み合わせを直す。逆にすると、労力の割に何も起きません。

    次に、探している人の言葉と、書いた人の言葉は違うこと。良い見出しを付けたつもりでも、それが検索で使われる言葉とは限りません。両立しないなら、場所ごとに出す文字を変える手があります。

    そして、一般論は条件付きの正解だということ。規模や状況が違えば逆に働きます。自分の数字に当てはめてから採用するべきです。

    最後に、確かめる前に成果を語らないこと。やったことと、効いたことは別です。記録として残す価値があるのは、前者を正確に書いておくことのほうだと思います。

  • 登録してから、広告を出すまで

    登録してから、広告を出すまで

    このサイトで、成果報酬型の広告を扱えるようにしました。

    手続きそのものは難しくありません。順番を間違えると手戻りになるところがいくつかあったので、そこを中心に残しておきます。

    この記事で扱うこと

    登録から掲載までの流れと、着手する順番。そして「何を紹介するか」を先に決めておくべき理由です。

    全体の流れ

    順番
    1. 掲載するサイトを整える     ← 審査で見られる
    2. ASPに登録する(サイト審査)
    3. 広告主ごとに提携を申し込む   ← 1件ずつ
    4. 承認される
    5. リンクタグを取得する
    6. 記事に置く
    7. 広告であることを表示する

    時間がかかるのは2と4です。どちらも相手の審査待ちなので、こちらからは進められません。待っている間に何をやっておくかで、承認後の速さが変わります。

    先にやっておくべきだったこと

    プライバシーポリシー

    これが最初です。広告を出すかどうかに関係なく、アクセス解析でCookieを使い、問い合わせフォームで個人情報を受け取っているなら、すでに必要になっています。

    広告の話が出てから慌てて作ることになりました。順番としては、サイトを公開した時点で用意しておくものです。

    広告であることを示す仕組み

    2023年10月から、広告を広告と分かる形で示すことが必要になりました。書き忘れると規制に触れます。

    本文に手で書く方法もありますが、手で書くものは、いつか書き忘れます。記事にタグを付けたら自動で表示が出る形にしておくと、忘れようがなくなります。

    これは提携が決まる前に作れます。実際、先に作っておいたので、承認後は記事にタグを付けるだけで済みました。

    何を紹介するかを決める

    ここがいちばん大事だと思います。「実際に使っているものだけ」と先に決めました。

    使っていないものを紹介できない理由

    このサイトは、書いた人が何を考えて作ったかを読んでもらう場所です。使ったことのないものを勧めた瞬間、他の記事も同じ調子で書かれていると思われます。

    1件の報酬と、全記事の信頼が釣り合いません。

    この条件で残るものは、多くありません。実際に契約しているサービスのうち、扱いのあるものだけになります。選択肢が減るのは、条件が効いている証拠だと考えることにしました。

    1つの広告主を、複数の記事に置くとき

    紹介できるものが少ないと、同じ広告主を複数の記事に置くことになります。ここで手を抜くと、同じ文面が何ページにも並びます。

    読者からは「どの記事にも同じ広告が挟まっている」としか見えません。検索エンジンから見ても、同一の内容が複数ページに散っている状態です。

    そこで、記事ごとに違うことを書く形にしました。企画の記事には選定の基準を、構築の記事にはつまずいた点を、公開の記事には契約前に知りたかったことを。どれもその記事で扱っている内容の延長線上にあります。

    この形なら、追記そのものが記事の情報量を増やします。

    置かない記事を決める

    候補に挙げた記事のうち1本を外しました。URLの処理に関する記事で、ドメインにもサーバーにも触れていません。

    ここに広告を置くと、内容と無関係な広告を挟んだことになります。読んだ人の信頼を削る割に、クリックもされないはずです。

    置ける場所すべてに置かない

    掲載できる場所の数と、掲載すべき場所の数は違います。文脈が合わないところに置くと、合っている場所の説得力まで下がります。

    収益の見込みについて

    正直に書くと、この規模のサイトで大きな金額にはなりません。

    それでも意味があると考えたのは、仕組みを一度通しておくと、判断の材料が手に入るからです。何がクリックされ、何がされないか。どの記事から動きがあるか。これは推測では分かりません。

    そして、こうして手順と判断を書き残せます。

    今回の学び

    まず、待ち時間のある手続きは、待つ前に準備を終えること。審査は自分では進められません。その間にできることを先に片付けておくと、承認された日に掲載できます。

    次に、条件を先に決めておくこと。「実際に使っているものだけ」を後から決めると、すでに置いたものを見直すことになります。基準は、選ぶ前に決めるから機能します。

    そして、忘れうることは、忘れられない形にすること。広告の表示は、書き忘れが規制に触れます。手で書く運用にした時点で、いつか漏れます。

    最後に、置ける場所すべてに置かないこと。数を増やすほど1件あたりの説得力は下がります。合う場所にだけ置くほうが、結果として届きます。

  • 分類は、探す人の手がかりではない

    分類は、探す人の手がかりではない

    用語集が116語になりました。分野ごとに8ページへ分けてあります。

    ある日、自分で「WAFってどこに書いたっけ」と探して気づきました。分野を当てないと、たどり着けません。

    この記事で扱うこと

    分類が誰のためのものかという話と、検索をブラウザ側に置いた判断、そして「打ち方の違いで見つからない」を潰すための文字のならし方です。

    分類は、書く側の都合でできている

    8つの分野は、書くときには役に立ちました。どこに何を書くかが決まり、抜けにも気づけます。

    しかし探す側から見ると、事情が違います。

    WAFを調べたい人がやること
    用語集を開く
      ↓
    8つの分野から、それらしいものを選ぶ  ← ここで当て推量
      ↓
    違ったら戻ってやり直す

    調べたい語が決まっている人にとって、分類は遠回りです。「WAFはセキュリティの話だ」と分かっている人は、そもそもWAFを調べません。

    整理した本人にしか使えない整理

    分類は、作った人には自明です。だから使いにくさに気づきません。自分で探して詰まって初めて、これは自分用の並べ方だったと分かりました。

    検索を、ページの先頭に置いた

    入力するとその場で絞り込まれ、押せば該当の語まで直接飛びます。分野の一覧は、検索していないときだけ出します。

    絞り込んだ結果の下に一覧が残っていると、どこまでが結果なのかが分からなくなるためです。

    打ち方の違いで、見つからないようにしない

    ここに手間をかけました。同じ言葉でも、打ち方は人によって違います。

    入力 探しているもの
    キャッシュ / きゃっしゅ / キャッシュ キャッシュ
    waf / WAF / WAF / わふ WAF
    resize / リサイズ ResizeObserver

    これを別物として扱うと、「あるのに見つからない」という結果になります。本人からすれば、無いのと同じです。

    比べる前に、全角と半角、大文字と小文字、カタカナとひらがなを一方に寄せています。読み(ひらがな)と、URLに使っているローマ字のIDも検索対象に含めました。日本語入力では変換の途中でも文字が届くので、確定前のひらがなでも当たるようにしてあります。

    なぜブラウザ側で絞り込むのか

    検索といえばサーバーに問い合わせる形が思い浮かびますが、今回は全部のデータを最初に渡してしまう形にしました。

    渡すもの
    語 + 読み + 1行の説明 + 置き場所  × 116語
    = 十数キロバイト(記事1本の本文より小さい)

    この量なら、最初に渡しても負担になりません。1文字打つたびに通信する必要がなくなり、待ち時間がゼロになります。

    規模が変われば、答えも変わる

    これは116語だから成立する判断です。数千語になれば、最初に渡す量が重くなり、サーバー側で絞り込む形が正しくなります。

    いまの規模で正しいことを選び、変わったら選び直すほうが、最初から大きく作るより速く進めます。

    残った引っかかり

    ひとつ、きれいでない点があります。用語の本文はCMS、検索用の索引はコードと、置き場所が分かれました。

    語を1つ足すには、両方を更新する必要があります。片方だけ直すと食い違います。

    いまは116語で、更新も自分1人なので回せます。ただしこれは「気を付ける」で運用している状態で、いつか間違えます。数が増えるか、更新する人が増えたら、索引をCMSから作る形へ変えるつもりです。

    今回の学び

    まず、分類は書く側の道具で、探す側の道具ではないこと。整理した本人には自明なので、使いにくさに気づけません。自分で探して詰まるまで分かりませんでした。

    次に、「あるのに見つからない」は、無いのと同じこと。打ち方の違いは利用者の間違いではありません。揃えるのは、こちら側の仕事です。

    そして、いまの規模で正しいものを選ぶこと。将来を見越して大きく作ると、そのぶん今日が遅くなります。変わったときに選び直せる形にしておけば十分です。

    最後に、気を付けて運用している場所は、書き留めておくこと。本文と索引が分かれている件は、いま把握しているから回るだけです。忘れた頃に食い違います。

  • 最初の画面に、本文が無かった

    最初の画面に、本文が無かった

    記事ページを開いたときに何が見えているかを、実際に測りました。

    測ったもの 値
    画面の高さ 723px
    本文が始まる位置 772px
    先頭のアイキャッチ画像 455px

    最初の画面に、本文が1文字も出ていませんでした。タイトルと日付と画像で埋まっていて、文章はスクロールしないと始まりません。

    この記事で扱うこと

    アイキャッチを消した理由、コードブロックにコピーボタンを付けた理由、見出しに個別リンクを足した理由、そして関連記事の選び方を日付から変えた理由です。

    1. アイキャッチを、記事ページから消した

    455pxは画面の6割です。ここを何が占めているかを考え直しました。

    このサイトのサムネイルは、記事タイトルを文字として描いた画像です。つまり、すぐ上の見出しと同じ内容を、画像でもう一度見せていたことになります。

    同じことを二度言うために、画面の6割を使っていた

    検索から来た人は「探している答えがここにあるか」を数秒で判断します。その数秒に見えているのがタイトルの繰り返しでは、判断する材料がありません。

    画像そのものは、記事一覧のカードとSNSで共有されたときの表示に使っています。作るのをやめたのではなく、本文を読む画面には置かないという判断です。

    2. コードブロックに、コピーボタンを付けた

    ある記事にはコードブロックが25個ありました。コマンドや設定値は、読むためではなく手元で使うために載せています。

    選択してコピーもできますが、折り返しのある長い行では取りこぼしやすい。ボタンを1つ足すだけで、この摩擦が消えます。

    ひとつ決めたのは、クリップボードが使えない環境ではボタンを出さないことです。押しても何も起きないボタンは、無いより悪いので。

    3. 見出しに、その見出しへのリンクを足した

    見出しが12個ある記事で、「この部分を見てほしい」と人に伝える手段がありませんでした。記事のURLしか送れず、相手は自分で探すことになります。

    用語集では語ごとに直接指せるよう整備したのに、記事側は未対応でした。同じ問題です。

    実装は、目次を組み立てる処理の中で一緒に埋め込みました。表示のあとにブラウザ側で差し込むこともできますが、そのぶん読み込むJavaScriptが増えます。すでに文字列を組み立てている場所があるなら、そこで済ませるほうが軽い。

    4. 関連記事を、日付ではなく内容で選ぶ

    これまで記事の末尾には「1つ新しい記事」と「1つ古い記事」だけを出していました。

    公開日が近いことと、内容が近いことには関係がありません。直前に書いた記事がまったく別の話題、ということは普通に起きます。

    タグの重なりを2点、カテゴリの重なりを1点として、上位3件を出すようにしました。

    なぜタグを重く見るか
    カテゴリ: 技術系 … ほぼ全記事が同じ
    タグ    : dns, seo, nextjs … 話題が分かれる

    カテゴリだけで判断すると、ほぼ全記事が等しく「関連」になります。粗い区分は、近さを測る物差しになりません。

    数を揃えるために、関係ない記事を混ぜない

    重なりが1つも無い記事は出しません。3件に満たなければ、その数だけ出します。1件も無ければ、セクションごと出しません。

    「関連記事」という見出しは、書いてあることが本当である前提で読まれます。体裁のために埋めると、その前提が崩れます。

    今回の学び

    まず、自分のページを、来た人の目で測ること。作っている側は上から下まで知っているので、最初の画面に何が見えているかを意識しません。数字にすると一目で分かります。

    次に、同じ内容を二度見せていないかを疑うこと。タイトルの画像とタイトルの文字は、別々に作ったので気づきませんでした。並べて初めて重複だと分かります。

    そして、片方で解決したことは、もう片方でも起きていること。用語集では直接指せるように整備したのに、記事では手つかずでした。同じ問題は、場所を変えて何度も出てきます。

    最後に、物差しが粗いと、何も測れないこと。全記事が同じ値を持つ項目で並べ替えても、順番は決まりません。分類は、細かさがそろって初めて役に立ちます。

  • ページを消すとき、一緒に消えるもの

    ページを消すとき、一緒に消えるもの

    実績とスキルの個別ページを、トップページの中へ統合しました。

    作業自体は「セクションにidを付けて、ページを2枚消す」だけです。消すほうに、決めることが集まっていました。

    この記事で扱うこと

    個別ページを持つ価値をどう判断したか、ページを消すときに一緒に消えてしまうもの、そして統合したあとに出た「リンクを押しても動かない」問題です。

    同じ内容が、2つのURLにあった

    トップページには、もともと実績・スキル・プロフィールのセクションがあります。そのうえで /projects と /skills という個別ページも持っていました。

    個別ページを持つ価値は、そこにしかない情報があるかで決まります。実績が20件あって絞り込みや並べ替えが要るなら、独立したページに意味があります。

    しかし実績は数件で、当面増える見込みもありません。結果として、ほぼ同じ内容が2か所にある状態でした。

    同じ内容が2つあると、選ばせることになる

    検索エンジンから見ると、似た内容のページが2つあります。どちらを検索結果に出すべきかを判断させることになり、評価も2つに分かれます。

    読む人にとっても、メニューの「実績」を押した先が、直前まで見ていたトップの内容とほぼ同じ、というのは肩透かしです。

    消すと、一緒に消えるもの

    ここが本題です。ページを削除すると、そのURLは404になります。失われるのは中身だけではありません。

    URLに付いていたもの 削除したとき
    検索エンジンからの評価 引き継がれず消える
    他サイトから貼られたリンク 404へ向かう
    ブックマーク・履歴 404が出る

    URLは外から指される名前です。中を整理した都合で、外からの参照を無効にしてよい理由にはなりません。

    そこで、旧URLを新しい位置へ転送する設定を入れました。

    転送の設定
    /projects  →  /#projects
    /skills    →  /#skills

    これで評価は転送先へ引き継がれ、古いリンクを踏んだ人も目的の場所に着きます。

    恒久か、一時的か

    転送には「もう戻らない」と「一時的に別の場所を見せている」の2種類があります。今回は戻す予定が無いので恒久を選びました。

    恒久転送は、ブラウザが覚える

    恒久として返すと、ブラウザはその対応を記憶します。次からはサーバーに聞かずに転送先へ行きます。速い代わりに、あとで気が変わっても、記憶を持っている人には届きません。

    迷いがあるうちは一時的な転送にしておくほうが安全です。恒久にするのは、本当に戻さないと決めてからで遅くありません。

    sitemapからは外した

    細かい点ですが、転送するURLを一覧に載せたままにしませんでした。

    sitemapは「このURLを登録してほしい」という一覧です。そこに転送するURLを書くと、「登録してほしい」と「そこへ行くな」を同時に伝えることになります。矛盾した指示は、送らないほうが良いはずです。

    統合したら、リンクが動かなくなった

    ここで問題が出ました。トップページ以外から「実績」を押しても、目的の場所へ行きません。

    原因は、ページの移動の仕方でした。

    同じ「#つきリンク」でも、起きることが違う
    同じページの中     → ブラウザが自分でスクロールする
    別のページから来た → 画面を読み込み直さず中身だけ差し替える
                         = ブラウザは「移動した」と思っていない
                         = URLの # を見て動いてくれない

    加えて、移動した直後は画面の先頭に戻されます。何もしないと「トップページの一番上に着いただけ」という結果になります。

    そこで、移動後にURLの # を読んで、その位置までスクロールさせる処理を足しました。飛び先がまだ描画されていない場合に備えて、1回だけ待って再試行しています。

    仕組みが変わると、当たり前が当たり前でなくなる

    # つきのリンクは、HTMLの最初期からある機能です。動いて当然と思っていました。

    しかし「画面を読み込み直さずに中身を差し替える」作りにした時点で、ブラウザが担当していた仕事の一部を、こちら側が引き取っています。引き取ったことに気づいていないと、こういう抜けになります。

    着地の位置も直した

    もうひとつ。アンカーで飛んだ先が、貼り付いたヘッダーの裏に隠れていました。

    飛び先の位置を計算するとき、ブラウザはヘッダーの存在を考慮しません。要素の上端を画面の上端に合わせるだけです。

    飛んだときだけ余白を確保する指定があるので、ヘッダーの高さぶんを足しました。

    今回の学び

    まず、個別ページを持つ価値は、そこにしかない情報があるかで決まること。ページ数が多いこと自体には価値がありません。同じ内容が複数の場所にあると、評価も注意も分散します。

    次に、URLは外から指される名前なので、中の都合で無効にしないこと。これはアンカーIDのときと同じ話でした。指す側は、指される側の事情を知りません。消すなら、行き先を用意してから消します。

    そして、恒久的な指定は、取り消しにくいこと。恒久転送はブラウザに記憶されるので、あとから変えても届かない相手が出ます。迷いがあるうちは一時的にしておく判断があります。

    最後に、仕組みを変えたら、ブラウザ任せだった部分を確認すること。画面を読み込み直さない作りにした時点で、いくつかの仕事がこちら側に移っています。移ったことに気づかないまま「昔から動くもの」として扱うと、静かに動かなくなります。

  • ゆっくり読む人ほど、読了にならなかった

    ゆっくり読む人ほど、読了にならなかった

    「ゆっくり読むと、読了にならないのではないか」。自分で読み返していて、そう思いました。

    調べたところ、そのとおりでした。丁寧に読む人ほど読了にならず、勢いよくスクロールした人ほど読了になるという、逆の作りになっていました。

    この記事で扱うこと

    割合で測るときに何を分母にするかで意味が変わるという話と、「最後まで到達した」と「読み終えた」を分けて考えた結果です。

    元の判定

    読了は、こう判定していました。

    元の計算
    進捗 = スクロール位置 ÷ (ページ全体の高さ − 画面の高さ)
    
    進捗が 95% を超えたら読了

    一見、妥当に見えます。95%にしているのも、末尾ぴったりまで行かなくてよいようにという配慮でした。

    実際に測ってみた

    推測で直すと、原因が別にあったときに気づけません。実際の記事のページで数字を出しました。

    測ったもの 値
    ページ全体の高さ 7,609px
    本文の高さ 6,153px
    本文より下に残っている高さ 684px
    本文を読み終えた時点の進捗 89.9%

    本文を最後の1行まで読んでも、89.9%にしかなりません。95%に届くには、そこからさらに344px下——前後の記事へのリンクと、フッターの中まで進む必要がありました。

    なぜ「ゆっくり」だと届かないのか

    ここが今回の肝でした。読む速さと、スクロールの止まる位置には関係があります。

    同じページでも、止まる場所が違う
    勢いよくスクロールした人
      → 慣性でページの最下端まで滑る → 100% → 読了
    
    文章を追って読んだ人
      → 本文の最後の行で手を止める   → 89.9% → 読了にならない

    速く動かした指は、そのまま惰性でフッターまで運ばれます。一方、読んでいる人は読むものが無くなった時点で止まります。当然の行動です。

    分母に、読まないものが入っていた

    ページ全体の高さには、フッターも、前後の記事へのリンクも、一覧へ戻るリンクも含まれます。どれも「読む」対象ではありません。

    測りたかったのは「本文をどこまで読んだか」なのに、分母は「ページをどこまで動かしたか」でした。名前は進捗でも、中身はスクロール量です。

    分母を本文に変えた

    基準を、ページ全体から本文の高さに変えました。

    新しい計算
    進捗 = (画面の下端 − 本文の開始位置) ÷ 本文の高さ

    本文の末尾が画面の下端に来た時点で100%になります。読み終えたら100%という、当たり前の対応になりました。

    ただし、これだけでは足りない

    末尾への到達だけを条件にすると、別の問題が残ります。目次から末尾の見出しへ飛んだ場合も、一気に下まで送った場合も、読了になります。

    「画面が下まで移動した」ことと「読み終えた」ことは、別のできごとです。

    そこで条件を2つにしました。

    条件 これが無いと
    本文の末尾まで到達している 開いて放置しただけで読了になる
    一定時間、実際に見ている 下まで送っただけで読了になる

    時間の基準は読了目安の4分の1にしました。8分の記事なら2分です。速く読む人を弾かない程度に緩く、しかし一瞬で下まで送った操作は通らない、という線を狙っています。

    「開いていた時間」ではなく「見ていた時間」

    単純に開いてからの経過時間で測ると、タブを開いたまま放置した時間まで読書時間になります。それでは条件の意味がありません。

    ブラウザには「このページがいま見えているか」を知る手段があります。見えている間だけ加算するようにしました。席を外して戻ってきた人が損をしません。

    一度到達したことを、忘れないようにする

    実装中に、条件が2つになったことで生まれる穴に気づきました。

    2つの条件は、同時に満たされるとは限りません。先に末尾まで読み、そのあと上に戻って読み返している最中に時間の条件を満たすことがあります。

    このとき現在位置だけを見ていると、「いま末尾にいないので読了ではない」と判定されます。一度は最後まで読んだという事実が、位置を戻した瞬間に消えてしまいます。

    起きたことは、消さずに覚えておく

    到達はできごとで、位置は状態です。できごとを状態から読み取ろうとすると、状態が変わったときに失われます。

    「一度でも到達したか」を別に記録するようにしました。読み返しても消えません。

    高さが変わることも見るようにした

    もうひとつ。本文の高さは、読んでいる最中にも変わります。画像が後から読み込まれる、目次を開く、画面を回す。

    元の実装は画面サイズが変わったときしか計算し直していませんでした。画像の読み込みでは、その通知は来ません。

    要素の大きさが変わったこと自体を教えてくれる仕組みに変えました。高さがずれたまま古い値で判定し続けることが無くなります。

    表示のほうも、記録に合わせた

    最後に、細かいけれど気持ち悪い食い違いを直しました。

    画面の「読了済み」という表示は、残り0%になった時点で出ていました。しかし実際に記録されるかどうかは、時間の条件も見ています。

    つまり画面には読了済みと出ているのに、記事一覧には読了マークが付かない状態があり得ました。

    表示のほうを、記録に従わせるようにしました。2つの真実を持たない、というだけの話です。

    今回の学び

    まず、割合で測るなら、分母が何かを疑うこと。今回は分母に、読む対象でないものが1割ぶん入っていました。式は正しく動いていて、測っているものが違っただけです。正しく計算された、意味の違う数字がいちばん見つけにくいと思います。

    次に、推測で直さず、まず測ること。「95%は厳しすぎるから90%に下げよう」でも症状は消えたはずです。しかしそれは、フッターの高さが変わるたびに再発します。89.9%という数字を出したから、分母の問題だと分かりました。

    そして、操作と、意味を区別すること。「下までスクロールした」は操作で、「読み終えた」は意味です。操作から意味を推し量るときは、必ずずれが出ます。ずれを埋める条件が要ります。

    最後に、できごとは、状態から読み取らないこと。一度起きたことは、現在の状態を見ても分からなくなることがあります。起きた時点で記録しておけば、あとから位置が変わっても失われません。

  • 測れるもので代用すると、測りたいものから離れる

    測れるもので代用すると、測りたいものから離れる

    「記事を最後まで読んだ人が何人いるか」を知りたい、というだけの話でした。単純に見えたので、すぐ作れると思っていました。

    実際には4回作り直しています。そのたびに別の壊れ方をしました。

    この記事で扱うこと

    読了の判定を作り直した4回ぶんの経緯と、そのたびに何を見落としていたかです。最後に、そもそも何を測ろうとしていたのかを整理します。

    1回目:下までスクロールしたかで測った

    最初は素直に、ページの何%までスクロールしたかで判定しました。95%まで来たら読了、という形です。

    これがうまくいきませんでした。分母にしていたページ全体の高さには、本文の下にある前後記事のリンクや一覧へ戻るリンク、フッターまで含まれています。実測すると、その下側だけで約680pxありました。

    分母に、読むものではないものが入っていた

    本文を最後まで読み終えても、進捗は90%前後にしかなりません。100%にするには、読むもののないフッターまでスクロールする必要がありました。

    勢いよくスクロールする人は慣性で最下端まで行くので満たせます。一方、文章を追って読む人は本文の終わりで手を止めます。ゆっくり読む人ほど読了にならないという、目的と逆の結果になっていました。

    2回目:本文の高さを分母にした

    分母を本文だけに変えました。本文の末尾が画面の下端に来た時点で100%になります。読み終えれば100%、という当たり前の対応になりました。

    ただ、これで別の穴が開きます。目次から末尾へ飛んだ場合も100%になります。位置だけを見ている限り、そこに至った経緯は分かりません。

    3回目:滞在時間の条件を足した

    そこで「そのページを実際に見ていた時間が一定以上ある」を条件に加えました。一瞬で駆け抜けた操作を弾くためです。

    条件が2つになった瞬間、画面の表示と記録がずれ始めました。

    回 何で判定したか そこで抜けたもの
    1 ページ全体のスクロール率 読む人ほど到達しない
    2 本文のスクロール率 飛んだ人も通る
    3 本文の到達+滞在時間 表示と記録がずれる
    4 同上(時間を緩和) 読まずに時間だけで通る

    進捗のバーは位置だけを表しているので、末尾に着いた瞬間に満杯になります。しかし記録は時間の条件を満たすまで行われません。バーは終わっているのに、読了済みにならないという食い違いが画面に残りました。

    条件を足すと、それを表す場所も増える

    判定に条件を足すのは簡単ですが、画面に出している表示のほうは1つのままでした。

    1つの表示で2つの条件を表そうとすると、必ずどちらかの状態を隠すことになります。隠された側が読み手には「動かない」ように見えます。

    間に挟まった、数字の問題

    ずれを隠そうとして、記録される前は「あと1%」で止める、という処理を入れました。0%と出しているのに読了済みに変わらない、という矛盾を避けるためです。

    これは失敗でした。今度は「1%のまま動かない」という別の分かりにくさになりました。残っていないものを数字で表そうとしたのが、そもそもの間違いでした。

    数字で表せない状態は、言葉で書く

    「残り」は数字で表せますが、「末尾には着いたが、まだ記録されていない」は数字ではありません。

    ここは数字をやめて、状態をそのまま言葉にするべき場所でした。無理に数値化すると、動かない数字という嘘が残ります。

    4回目:今度は、読まずに完了するようになった

    時間の条件を緩めたところ、逆の症状が出ました。読み終えていないのに、時間の経過だけで完了になります。

    設計上、位置と時間の両方を満たさないと読了にはならないはずです。それでも時間だけで通るということは、位置の条件が常に成立しているとしか考えられません。

    条件が2つあると、片方が壊れたときに気づけない

    2つの条件を「かつ」で結ぶと、片方が常に真になっても、全体としては動き続けます。残った条件が単独の判定として働くだけで、エラーにはなりません。

    気づけたのは、症状が「時間だけで通る」という形で表に出たからです。出方が違えば、そのまま気づかずにいた可能性があります。

    そもそも、測れるもので代用していた

    ここまで来て、やっと本題に気づきました。

    知りたいのは「読んだか」です。しかし測れるのは「画面がそこを通ったか」と「そのページが開かれていた時間」だけです。読んだかどうかは、ブラウザからは直接見えません。

    つまり最初から、測りたいものを測れるもので代用していました。代用そのものは避けられません。問題は、代用していることを忘れて、条件を足したり引いたりしていたことです。

    代用だと分かっていれば、条件の足し方が変わる

    条件を足すたびに「これは読んだことの何を近似しているのか」を書いていれば、位置と時間が別々の近似だと分かったはずです。

    別々の近似を「かつ」で結べば、片方が外れたときに残りが単独で判定を下します。足したのは精度ではなく、壊れ方の種類でした。

    いま考えている形

    次は、時間をやめて経路を見ようと思っています。

    記事をいくつかの区画に区切り、そのすべてが画面を通ったかどうかを判定します。目次から末尾へ飛べば途中の区画を通らないので読了になりません。ゆっくり読む人は必ず全区画を通るので、確実に読了になります。

    時間に頼らずに「飛ばした人を通さない」と「速く読む人を弾かない」の両方が満たせます。何より、近似しているものが1種類になるので、片方が壊れて気づかない、という形にはなりません。

    今回の学び

    まず、測りたいものと測れるものは違うこと。読んだかどうかは見えないので、必ず何かで代用します。代用だと自覚していないと、精度を上げているつもりで壊れ方を増やすことになります。

    次に、条件を「かつ」で結ぶと、壊れても動き続けること。片方が常に真になっても例外は出ません。残った条件がそのまま判定として働くので、症状が出るまで気づけません。条件を足すときは、それぞれが単独になったときに何が起きるかを見ておく必要がありました。

    そして、判定に条件を足したら、表示も足すか、表示のほうを言い換えること。1つの表示で2つの状態を表そうとすると、必ずどちらかが隠れます。隠れた側は、読み手には「壊れている」ように見えます。

  • 奥行きは、影だけの話ではない

    奥行きは、影だけの話ではない

    ダークモードを入れたとき、明るい配色で効いていた影が暗い背景でほとんど消えました。境目が分からなくなり、カードが背景に溶けます。

    そのとき初めて、自分が奥行きを影だけで作っていたことに気づきました。手段が1つしかないと、その手段が使えない場面でやり直しになります。

    この記事で扱うこと

    面を分けるための手段を並べて、それぞれが何で差をつけているか、どこで効かなくなるかを整理します。そのうえで、どういう順番で選べばいいかを決めます。

    「切り分ける」と「浮かせる」は別の目的

    まずここを混ぜないほうがいいと思いました。見た目は似ていますが、伝えたいことが違います。

    やりたいこと 読み手に伝えたいこと 向いている手段
    切り分ける ここまでとここからは別の話だ 余白、背景の明度差、罫線
    浮かせる これは本文より手前にある一時的なものだ 影、ぼかし、重なり

    切り分けたいだけの場所に影を付けると、本文と同じ平面にあるはずのものが浮いて見えます。逆に、閉じれば消えるものを罫線で区切ると、ページの一部として居座って見えます。

    手段を並べて、効かない場面を書き出す

    使える手段はそれほど多くありません。並べたうえで「どこで効かなくなるか」を一緒に書いておくと、選ぶときに迷わなくなります。

    手段 何で差をつけているか 効かなくなる場面
    余白 距離 画面が狭く、余白を取る余地がないとき
    背景の明度差 面の明るさ 差が小さすぎるとき。ただし配色を問わず成立する
    罫線 線 本数が増えたとき。画面が格子に見える
    枠線と角丸 囲い 入れ子にしたとき。内と外の区別が付かなくなる
    影 光の当たり方 暗い配色。背景より暗い影は見えない
    半透明とぼかし 前後関係 背景が単色のとき。透けても何も見えない
    影だけが、配色を前提にしている

    影は「上から光が当たっている」という状況を描いたものです。明るい面に暗い影を落とすから浮いて見えるのであって、面そのものが暗ければ落とす先がありません。

    他の手段は配色が変わっても意味を保ちますが、影だけは配色とセットです。ここを分けて考えていなかったのが、今回つまずいた原因でした。

    いちばん強いのは余白だった

    意外に思われるかもしれませんが、切り分ける力がいちばん強いのは余白です。

    近くにあるものは同じ仲間、離れているものは別の仲間、と読み手は勝手に判断します。線も影も無くても、距離だけで境界は伝わります。実際、罫線を引きたくなった場所の多くは、余白を広げるだけで解決しました。

    それでも線や面を足したくなるのは、余白が足りていないときです。狭いところに詰め込んだまま境界だけを描こうとすると、線が増えて画面が窮屈になります。順番としては、まず余白を疑うほうが早いと思います。

    暗い配色でも残るのは、明度差だった

    ダークモードで見直したとき、最後まで機能していたのは背景の明度差でした。

    明るい配色では、白い本文の上に少しグレーがかった面を置くと「一段下がった」ように見えます。暗い配色ではこれが逆になり、背景より少し明るい面が「一段上がった」ように見えます。

    明るいほうが手前、は暗い配色でも変わらない

    明暗を反転させると濃淡の関係も逆になりますが、「明るいほうが手前に見える」という関係だけは変わりません。

    だから、明るい配色では「背景より暗い面」で沈め、暗い配色では「背景より明るい面」で浮かせる。同じ考え方のまま、向きだけを入れ替えれば済みます。

    影のように配色ごとに作り直す必要がないので、迷ったらここに寄せるのが安全だという結論になりました。

    追従するものだけは、別の扱いが要る

    ひとつ例外があります。スクロールに追従して画面に貼り付くものです。

    このサイトでは、スマートフォンで目次が画面の上に貼り付きます。ここだけは本文の上を通過していくので、切り分けではなく前後関係を示す必要があります。少し透かして背景をぼかす指定を入れているのは、そのためです。

    透けて見えることで「下に本文が続いている」と分かり、ぼけていることで「いま読むのはこちらではない」と分かります。この2つはセットにして初めて意味を持ちます。透かすだけだと下の文字と重なって読みにくくなり、ぼかすだけだと下に何があるか分かりません。

    透過は、目立たなくするための手段ではない

    以前、追従しているあいだだけ目次を薄くする、という案を入れたことがあります。邪魔にならないようにするつもりでした。

    結果として、読みにくくなっただけで邪魔さは変わりませんでした。薄くしても場所は取り続けるからです。透過が答えになるのは「下が見えることに意味がある」ときだけで、「目立たせたくない」なら置く場所や大きさのほうを変えるべきでした。

    手段を重ねるほど、弱くなる

    ここが今回いちばん腑に落ちた部分です。

    ひとつの境界に、枠線を引いて、角を丸めて、背景を変えて、影を落とす。全部やれば強く分かれそうに思えますが、実際には逆でした。どの手段が境界を作っているのか分からなくなり、画面全体がぼんやりします。

    手段が増えるほど、他の場所との差も付けにくくなります。すべての箱が同じように装飾されていると、本当に浮かせたい1枚だけを浮かせる余地が無くなります。

    1つの境界には、1つの手段

    決めたのは単純な方針で、ひとつの境界を作るのに使う手段はひとつだけにする、というものです。

    面で分けたなら線は引かない。線で分けたなら背景は変えない。そうしておくと、あとから「ここだけ強調したい」と思ったときに、手段をひとつ足すだけで差が付きます。

    選ぶ順番を決めておく

    毎回考え直さなくて済むように、順番にしました。

    まず余白で足りないかを見ます。足りるなら何も足しません。次に、それが同じ平面の話なら背景の明度差で分けます。線を引くのは、面で分けると重くなる細かい区切りだけにします。

    手前に浮かせたいときだけ影を使い、その場合は明るい配色と暗い配色の両方で見え方を確かめます。追従して本文の上を通るものだけ、半透明とぼかしを使います。

    この順番にしてから、装飾で迷う時間がはっきり減りました。決めているのは見た目ではなく、何を伝えたいかのほうだからだと思います。

    今回の学び

    まず、奥行きの手段は、配色に依存するものとしないものに分かれること。影だけが光を前提にしていて、暗い配色では成立しません。手段を1つしか持っていないと、配色を増やした時点でやり直しになります。

    次に、いちばん強い区切りは、何も描かない余白だったこと。線を引きたくなったときは、たいてい余白が足りていませんでした。描き足す前に、空けられないかを先に見るほうが早いです。

    そして、手段を重ねると強くなるどころか弱くなること。全部の箱を同じように飾ると、本当に目立たせたい1つを目立たせる手段が残りません。1つの境界に1つの手段、と決めておくのは、いま作りやすくするためではなく、あとで差を付ける余地を残しておくためでした。