ブログ

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

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

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

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

    この記事で扱うこと

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

    全体の流れ

    順番
    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%という数字を出したから、分母の問題だと分かりました。

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

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

  • Cornix LP(白):打てなくなったのは、指ではなく手順だった

    Cornix LP(白):打てなくなったのは、指ではなく手順だった

    きっかけは自作キーボードでした。ネットで見かけて興味は湧いたのですが、部品を選んで組み立てるところまでやるのは難易度が高そうだと感じて、手が止まっていました。

    やりたいのは自作そのものではなく、分割配列とレイヤーを使ってみることのほうです。それなら完成品で確かめられます。注文したのが7月9日、手元に届いたのが9月5日でした。

    この記事で扱うこと

    自作ではなく完成品を選んだ理由、カラムスタッガード配列に移って何が崩れたか、崩れた場所が予想と違っていたこと、日本語と英語の切り替えをどこに置いたか、そして慣らすためにやったことです。

    試したいのは配列で、組み立てではなかった

    自作キーボードの記事を読んでいると、配列やレイヤーの話と、はんだ付けや部品選びの話が同じところに並んでいます。両方まとめて「難しそうなもの」に見えていました。

    分けて考えると、自分が知りたいのは前者だけです。組み立ては、そこへ行くための手段であって目的ではありません。完成品なら手段のほうを飛ばせます。

    もし配列が自分に合わなければ、そこで終わりにできます。合うと分かってから組み立てを考えればよく、順番としてはこちらのほうが安いはずでした。

    崩れたのは、指ではなく手順だった

    届いた日から使い始めて、最初に分かったのは「打てない」ではなく「打ち方を思い出せない」ということでした。指が動かないのではなく、指をどこへ出すかを決めている手順のほうが止まります。

    分割キーボードに移ると、まず手の置き場所が変わります。左右が離れるので、肩を開いたまま構えることになります。ここは変わることが分かっていたので、身構えていました。

    実際に困ったのはそこではありませんでした。手の位置にはすぐ慣れました。戻らなかったのは、指がどこへ行くかを決めている手順のほうです。

    いままで使っていたキーボードは、段ごとにキーが横へ少しずつずれて並んでいます。Cornix LPは、縦の列がまっすぐ揃っています。この違いは見た目としては小さいのですが、特定のキーだけを狙い撃ちで壊しました。

    Nだけが、いつまでも当たらない

    いちばん間違えたのがNです。

    これまでNは、右手の人差し指を少し左下へ潜り込ませるようにして打っていました。段がずれているので、その斜めの動きの先にNがあったからです。

    列がまっすぐ揃うと、その「左下へ潜る」動きの先にNはありません。頭ではNの位置を知っているのに、手はいままでどおりの斜めの動きを出します。知っていることと、打てることが別だと分かったのがこの瞬間でした。

    いままでのキーボード Cornix LP
    キーの並び 段ごとに横へずれる 縦の列がまっすぐ
    指の動き 斜めに潜り込む動きが混ざる まっすぐ上下に動かす
    覚え直すもの — キーの位置ではなく、指の出し方
    「慣れる」の中身が、想像と違っていた

    慣れるというのは、新しい位置を覚えることだと思っていました。実際にやっていたのは、すでに体に入っている動きを消す作業のほうです。

    覚えるのは足し算なので、時間をかければ進みます。消すのは引き算で、こちらは意識して同じ場所を何度も通らないと減りません。壊れたキーだけが何日も残ったのは、そのためでした。

    「ー」は、そもそもその場所にない

    もうひとつ引っかかったのが、長音の「ー」です。

    Nは位置が変わっただけですが、こちらは事情が違います。キーの数が絞られている配列なので、そのキーが同じ面に出ていません。別のレイヤーを押しながら打つことになります。

    日本語を書いていると「ー」は頻繁に出てきます。1文字打つのに指を2本使う状態がしばらく続いて、ここは位置を覚える以前の話でした。

    日本語と英語の切り替えは、レイヤー①のAとSに置いた

    設定でいちばん効いたのがここです。

    日本語と英語の切り替えを、レイヤー①のAとSに割り当てました。ホームポジションの左手そのままの位置なので、切り替えのために手を動かす必要がありません。

    AとSに分けたのは、押した結果がひとつに決まるようにするためです。ひとつのキーで交互に切り替える形にすると、いまどちらなのかを覚えていないと押せません。Aなら必ず一方、Sなら必ずもう一方にすれば、現在の状態を知らなくても正しく押せます。

    切り替えより、指定のほうが軽い

    交互に切り替える方式は、キーが1つで済むぶん得に見えます。ただし押す側は「いまどちらか」を持ち続けることになります。

    直接指定してしまえば、覚えておく必要そのものが消えます。キーを1つ余分に使いますが、頭のほうが軽くなりました。

    慣らしに使ったのは、ゲームだった

    Nと「ー」を直すために、寿司の名前がついたブラウザのタイピングゲームを使いました。

    ふだんの作業の中で直そうとすると、うまくいきません。書きたいことがあるので、打ち間違えたら直すことより先へ進むことを優先してしまうからです。間違えた動きが、そのまま通ってしまいます。

    ゲームなら、打つこと自体が目的になります。間違えればその場で分かるし、同じ文字が何度も出てきます。間違いを見逃せない状態を、わざわざ作るための道具として使いました。

    合わなかったところ

    まず、移行の期間は仕事が遅くなります。これは製品の問題ではありませんが、締め切りの近い時期に切り替えるものではないと思いました。

    それと、キーの数が絞られているぶんレイヤーの設計を自分でやることになります。買ってすぐ最適な状態にはならず、使いながら直していく前提のものです。ここを面倒だと感じるなら、合わない可能性が高いです。

    それと、この記事はまだ慣れている途中で書いています。Nと「ー」は日ごとに良くなっているところで、何日で元の速さに戻るかは、まだ言える段階にありません。

    同じように、左右を無線でつないだときの安定性と、電池の持ちが数か月後にどうなっているかも、いま判断できません。使い続けて分かった時点で、この記事に足します。

    今回の学び

    まず、難しそうに見えるものは、たいてい二つ以上が束ねられていること。自作キーボードが難しく見えていたのは、配列の話と組み立ての話が同じところに並んでいたからでした。分けてみると、試したいほうだけを完成品で先に取れます。

    次に、身についた動きは、知識では上書きできないこと。新しい位置を知っていても、手は前の動きを出します。覚え直すというより、前の動きを消す作業でした。

    そして、全体が変わっても、壊れるのは一部だけだということ。配列を丸ごと変えたのに、実際に困ったのはNと「ー」に集中しました。全部が等しく難しくなるわけではないので、どこが壊れたかを特定できれば、直す範囲はかなり小さくなります。

    さらに、状態を覚えさせる操作は、それだけで重いこと。交互に切り替える方式は操作の数こそ少ないのですが、押す前に現在の状態を思い出す必要があります。直接指定に変えたら、その手間がまるごと消えました。

    最後に、直したい癖は、本番では直らないこと。本番には別の目的があるので、間違いを見逃す動機が働きます。間違いを見逃せない場所を別に用意するほうが、結果的に早く済みました。

  • 長さが合っているのに、中身が壊れていた

    長さが合っているのに、中身が壊れていた

    作った画像を、ブラウザ越しにCMSへ上げる必要がありました。一度に送れない大きさだったので、分割して送り、向こう側でつなぎ直しています。

    つなぎ直した長さは、元のデータと1文字も違いませんでした。それでも上がった画像は真っ黒でした。

    この記事で扱うこと

    長さが合っているのに中身が壊れていた原因と、それを見つけるまでに遠回りしたこと。そして分割して送るときに、検証をどこに置くべきかです。

    長さが合うことは、無事の証明にならない

    最初に確認したのは長さでした。送った文字数と受け取った文字数が一致していたので、無事に届いたと判断しました。

    これが間違いです。どこかで1文字増えて、どこかで1文字減れば、長さは変わりません。実際に起きていたのはこれでした。

    確かめやすいことを、確かめたいことの代わりにしていた

    確かめたかったのは「中身が同じか」です。確かめたのは「長さが同じか」でした。長さは数えるだけで済むので、つい代わりに使ってしまいました。

    長さが違えば壊れていると分かりますが、長さが同じでも壊れていないとは言えません。片方向にしか使えない検査を、両方向に使っていました。

    どこで壊れたのかが分からない

    次に困ったのが、壊れた場所の特定です。

    全体をひとつの塊として扱っていたので、「どこかが壊れている」以上のことが分かりません。やり直すとしたら全体をやり直すしかなく、しかも同じ場所でまた壊れるかどうかは運任せになります。

    実際、一度送り直しても同じように壊れました。何が起きているか分からないまま、同じ操作を繰り返していました。

    分割して送るなら、検証も分割する

    やり方を変えました。送る側で分割したときに、各かたまりごとに短い検査値を計算して一緒に渡します。受け取る側は、つなぐ前にその場で照合します。

    全体だけを検証 かたまりごとに検証
    壊れたことに気づける すべて送り終えたあと そのかたまりを受け取った時点
    壊れた場所 分からない そのかたまりだと確定する
    やり直す範囲 全体 そのかたまりだけ

    これに変えた途端、壊れている場所が一発で出ました。しかも受け取り側が拒否を返すので、壊れたまま先へ進むことがなくなります。

    やり直しの範囲は、検証の粒度で決まる

    検証を全体にしか置かないと、失敗も全体になります。細かく検証すれば、失敗も細かくなります。

    分割する目的は「一度に送れないから」でしたが、分割したことの利点は、失敗を小さくできることのほうにありました。

    検証は、転送の「あと」ではなく「一部」にする

    ここが今回の考え方の変化でした。

    最初は、送り終えてから確かめる、という順番で組んでいました。転送と検証が別の工程になっていて、間に「壊れたまま進む余地」があります。

    いまは、検査値が合わないかたまりは受け取らない形にしています。検証は転送の後工程ではなく、転送の一部です。こうすると「受け取れた」と「正しい」が同じ意味になります。

    形式として正しくても、中身が正しいとは限らない

    もうひとつ、別の層の話があります。

    検査値が合って、データが完全に届いた。そこまで確認しても、上がった画像が意図したものかは、まだ分かりません。実際、最初に壊れた画像は「画像ファイルとしては正しい形式」で、開くこともできました。中身が真っ黒だっただけです。

    そこで、送り先に登録する前に、実際に画素を読むようにしました。画面には出さず、いくつかの座標の色を取って、想定した配色になっているかを見ます。真っ黒なら、そこで止まります。

    出す前に、出すものを見る

    「形式として妥当か」と「意味として正しいか」は別の検査です。前者は自動で分かりますが、後者は中身を見に行かないと分かりません。

    面倒に見えますが、やっているのは数点の色を読むだけです。壊れたものを世に出してから気づくコストと比べれば、はるかに安く済みます。

    今回の学び

    まず、長さの一致は、内容の一致ではないこと。確かめやすい指標を、確かめたい事実の代わりに使うと、一致しているのに壊れている状態を見逃します。

    次に、失敗の大きさは、検証をどの粒度に置いたかで決まること。全体にしか検証を置かなければ、やり直しも全体になり、原因も特定できません。分けて送るなら、分けて確かめるべきでした。

    そして、検証は工程の後ろに置くと、壊れたまま進む余地が残ること。転送の一部にしてしまえば、受け取れたことがそのまま正しさの証明になります。順番を変えただけで、確認という作業そのものが要らなくなりました。

    最後に、形式の正しさと意味の正しさは、別々に確かめる必要があること。壊れた画像は画像として開けました。開けることと、意図したものであることは、まったく別の話でした。

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

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

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

    実際には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つの手段、と決めておくのは、いま作りやすくするためではなく、あとで差を付ける余地を残しておくためでした。

  • 読む邪魔をしない

    読む邪魔をしない

    スマートフォンで自分の記事を読んでいて、気になることがありました。

    画面の上に、ヘッダーと目次がずっと貼り付いたままです。どちらも便利なつもりで置いたものですが、読んでいるあいだは、ただ場所を取っています。

    この記事で扱うこと

    常に出しておくものと、必要なときだけ出すものの分け方。「消す」ではなく「薄くする」を選んだ理由。そして、2つの追従する要素が重なったときに起きた、位置の食い違いです。

    貼り付いたものは、面積を占め続ける

    スマートフォンの画面の高さは、だいたい本文15〜20行ぶんです。そこにヘッダーが1行、目次のバーが1行居座ると、実際に読める範囲は1割ほど減ります。

    減るだけならまだしも、目次のバーはいま読もうとしている行の上に半透明でかぶさります。スクロールしている最中がいちばん邪魔です。

    3つの変更

    対象 前 後
    ヘッダー 常に表示 下へ読み進む間は引っ込む
    目次(スマホ) 常に同じ濃さ スクロール中だけ薄くなる
    先頭へ戻る 手段なし ボタンを出す

    1. ヘッダーは「量」ではなく「向き」で判断する

    最初に考えたのは「300pxスクロールしたら隠す」でした。単純ですが、これだと読み進めるほど隠れっぱなしになります。メニューを開きたくなったとき、ページの先頭まで戻ることになります。

    採用したのは、スクロールの向きで判断する方式です。

    判断の基準
    下へ読み進んでいる  → 隠す(読むのに要らない)
    上へ戻し始めた      → 出す(何かしたいはず)
    ページの先頭付近    → 必ず出す

    上へのスクロールは、たいてい「前に戻りたい」「別の場所へ行きたい」という合図です。その動作を、ヘッダーを呼び出す操作として兼ねさせています。新しい操作を覚えてもらう必要がありません。

    細かいが要る配慮が3つあった

    ひとつめはわずかな揺れを無視すること。指の震えや慣性の揺り戻しで数px動くたびに出し入れすると、ヘッダーが点滅します。6px未満の移動は無視しています。

    ふたつめは画面の端で引っ張ったとき。iPhoneでは画面の一番上でさらに引っ張ると、スクロール位置がマイナスになります。そのまま計算すると「上に動いた」と誤判定します。0で止めるようにしました。

    みっつめはメニューを開いているあいだは隠さないこと。開いた本人の操作でヘッダーごと消えたら、何が起きたのか分かりません。

    2. 目次は「消す」のではなく「薄くする」

    目次も同じように隠す案がありました。やめました。

    この目次のバーには読了の進捗も出しています。消すと、どこまで読んだかが分からなくなります。

    邪魔なのは「濃さ」であって「存在」ではない

    困っていたのは、文字の上に別の文字が重なって読めないことでした。薄くすれば下の文字は読めます。位置と進捗は視界の端に残ります。

    指を止めれば元の濃さに戻ります。スクロール中しか邪魔にならないものを、常時消す必要はありません。

    開いているときは薄くしません。開いているのは読むためではなく選ぶためなので、そこで薄くすると目的の見出しを探せなくなります。

    3. 2つの追従が、食い違った

    ここで問題が出ました。

    目次は「ヘッダーの高さ(56px)ぶん下」に貼り付く指定になっています。ヘッダーがそこにある前提です。

    ところがヘッダーは引っ込むようになりました。すると——

    ヘッダーが消えたあと
    画面の上端
       ↓
    (56pxの空白)   ← ヘッダーが居たはずの場所
       ↓
    目次のバー       ← 宙に浮いて見える

    目次だけが、意味のない隙間を空けて浮きます。

    状態を、渡さずに共有する

    ヘッダーが隠れているかどうかを、目次に伝える必要があります。素直に考えると「上から順に受け渡す」ですが、この構成では間にあるページ全体を作り替えることになります。

    選んだのは、ページ全体に1つの値を置く方法です。

    ヘッダーが書き、目次が読む
    ヘッダー: --header-offset = 3.5rem(表示中)/ 0rem(隠れている)
    目次    : 貼り付く位置 = --header-offset

    ヘッダーは自分の状態を書くだけ、目次はその値を見るだけです。お互いを直接知らないまま、位置だけが揃います。

    あえてTailwindを使わなかった箇所

    このサイトのスタイルはTailwind CSSで書いています。今回の位置指定も書けますが、1か所だけ普通のCSSにしました。

    理由は、壊れ方です。Tailwindのクラス名を書き間違えると、CSSが生成されないだけで、ビルドは成功します。

    気づけない壊れ方を選ばない

    位置指定が消えると、目次は貼り付くのをやめて一緒に流れて消えます。エラーは出ません。実際に記事を開いてスクロールするまで分かりません。

    この部分は今回いちばん確かめにくい場所だったので、綴り間違いで静かに消えない書き方を選びました。

    4. 先頭へ戻るボタン

    最後に、よくあるボタンを置きました。ここでも1つだけ気を付けた点があります。

    薄くして消したボタンは、見えないのに押せます。透明度を0にしただけでは、そこにある扱いのままです。キーボードで操作している人には、見えない項目に順番が回ってきます。

    見えないあいだは押せない・順番が回ってこない・読み上げられないの3つを揃えました。見た目と実体を一致させています。

    あわせて、端末の「動きを減らす」設定を尊重しています。滑らかに移動するのが心地よい人ばかりではありません。

    今回の学び

    まず、常に出しておくものと、必要なときだけ出すものを分けること。便利だから常に出す、を積み重ねると、本文が読める面積だけが減っていきます。何のために画面を開いているのかに戻って決めるべきです。

    次に、「隠す」の前に「薄くする」を検討すること。困っているのが重なりなら、濃さを変えるだけで解決することがあります。消してしまうと、その要素が持っていた別の役割まで一緒に失います。

    そして、動かすものが増えたら、位置の前提を疑うこと。固定されている前提で書いた数値は、片方が動き出した瞬間に嘘になります。今回は「ヘッダーの高さ」がそれでした。

    最後に、確かめにくい場所ほど、壊れたら気づく書き方を選ぶこと。同じ結果になる書き方が2つあるなら、間違えたときに黙って消えないほうを選ぶ価値があります。