7 ポイント 投稿者 GN⁺ 2025-04-05 | 1件のコメント | WhatsAppで共有
  • アンカーリンクは、単にボタンをクリックして見出しまでスクロールするという構造だが、実装時には実際に問題が発生する
  • 下部にある見出しはビューポート上端へ正確にスクロールされないため、UX の低下が起きる
  • これを解決するためにさまざまなアプローチを試し、次第により精巧で複雑な方式へ発展させていく

単純な解決策: パディングを追加

  • 下側の見出しがスクロールで届くように余白を追加する方式
  • デルタを計算して padding を追加すれば解決できる
  • ただし、デザインチームは不要な余白を嫌がるかもしれない

実用的な解決策: トリガーラインの移動

  • トリガーラインをビューポート下側へ移動し、下部の見出しがそこに届くよう調整する
  • 問題は、見出しがビューポートの最下部に位置してしまい、可読性が落ちること

改善案: 仮想トリガーポイントの生成

  • 実際の見出し位置はそのままにして、トリガーが発生する位置だけを上側へ移動した仮想位置を作る
  • 各見出しごとに異なる調整を適用できる柔軟性を確保
  • ただし最初の見出しは上に移動しすぎて新たな問題が発生する → 個別調整が必要

より良い方法: トリガー位置の比例移動

  • すべてのトリガーを同じだけ動かすのではなく、最初の見出しはそのまま、最後の見出しは最大限に移動
  • 中間の見出しは位置に応じて比例して移動する
  • 見出しの順序を維持し、スクロールで到達可能であることを保証するという条件を満たす
  • この方式はシンプルで実用的であり、ほとんどの場合にうまく機能する

高度なアプローチ: カスタムマッピング関数による最適化

  • トリガー位置を任意に 25% の位置へ置いたため、仮想位置が元の位置から離れすぎる可能性がある
  • これを解決するために、MSE(Mean Squared Error) を使った最適化アプローチを導入

損失関数の構成

  • Anchor Penalty: 仮想見出し位置が元の位置からどれだけずれたか
  • Section Penalty: セクション間の距離(スクロール長)がどれだけ変化したか
  • この 2 つの値を重み付けして最適なトリガー位置を導き出す

制約条件

  • ページ範囲内に収める
  • 最初の見出しは上へ移動しない
  • 見出しの順序を保持する

インサイト: 単純な比例移動の限界

  • 非常に長いページ(例: 聖書全体)では、ページ全体にわたって小さな移動を累積的に適用しなければならない非効率が生じる
  • ページが長いほど誤差が大きくなり、UX に悪影響を与える可能性がある

最終的な解決策: smoothstep ベースの可変マッピング関数

  • 各見出しの位置を 0〜1 の値に正規化し、それを基に調整率を計算する
  • Smoothstep 関数(S(x) = 3x² - 2x³) を使って滑らかな遷移を実現
  • 調整開始位置 a を設定し、その位置までは移動せず、それ以降で滑らかに増加させる
    • 例: a = 0.4 なら上位 40% の見出しは移動なし、下位 60% は段階的に調整
  • 結果として、上部の見出しは元の位置を維持し、下部の見出しには最大調整を適用 → 自然な UX を提供

検証とまとめ

  • 最終実装は、設計としての精巧さと実用性のバランスを備えたソリューション
  • もちろん、デザイナーからのフィードバックは「…とにかくちゃんと動けばいいかも」かもしれない
  • それでも少なくとも、このブログ記事は永遠に記憶される精巧なエンジニアリングの記録として残る

1件のコメント

 
GN⁺ 2025-04-05
Hacker Newsのコメント
  • バックエンド開発者としてフロントエンドの作業を見ると、ときどきその複雑さに驚かされる

    • 素晴らしい記事で実装もよくできているが、単純なスクロールにこれほど多くの複雑さを持ち込む必要があるのか疑問に思う
  • サイドナビゲーションの「アクティブなアンカー」表示のUX目的についての疑問

    • 読者が長いセクションの途中にいるとき、画面に見えていない見出しの代わりに現在のセクションを思い出させてくれる
    • これはスクロールした見出しではなく、画面に見えているセクションに応じて動作することを意味する
    • 小さなセクションが画面の大部分を占められない場合、アクティブ表示は役に立たないかもしれない
  • アンカーリンクの最も重要なUX機能は、他の人に送れてブックマークとして保存できることであるべき

    • 特定のセクションをブックマークできる機能は、ページ上部からスクロールしたりアンカーリンクをクリックしたりするよりはるかに便利
    • このWebサイトは #anchor-name URL を使っていないため、この機能を提供していない
  • Jiraのアンカー/パーマリンクにうんざりしてクリックしたが、似ているようで別の方式だった

    • キーボードでアンカーへ移動できない
    • 著者への質問: なぜHTML `` 要素ではなく、非インタラクティブ要素にJSイベントリスナーを使ったのか
  • メインページのコンテンツ下にパディングを追加するのが理想的

    • コンテンツの終端がビューポート下端に張り付く問題を解決できる
    • モバイルでは90vh、より大きな画面では50vhのマージンが適切
    • デスクトップでは90vhのマージンは不自然に見えるかもしれない
  • 現代のブラウザでは、テキストフラグメントを使ってページ内の特定部分を強調できる

    • Chromeではテキストをハイライトして右クリックし、「リンクをコピー」を選べばよい
    • アンカーの代わりに特定のテキスト部分を強調するために毎日使っている
  • 複数の「アクティブ」状態を許可することも可能

    • コンテンツが長ければ、2つのセクションのヘッダーがどちらも「アクティブ」状態になりうる
    • 短いコンテンツでは、強調される部分が多すぎる可能性がある
  • 他のコメントを読むのが面白い

    • モバイルでのサイトデザインが興味深く、問題解決の方法が明確に伝わる
    • ポップアップなしで技術的な内容を扱うブログを読むのは新鮮だ
  • Firefoxデスクトップでは、「美しいソリューション」が「中間セクション」を強調する

    • ページ下部に到達していないときでも、結論が完全に見えてしまう
    • 画面に見えているすべてのアンカーを強調するのが答えだ
  • 記事はすっきりしていて、ブログデザインのほうがさらに興味深い

    • 右寄せの方式は好みではないが、左側ポップアップのインラインアクティベーションはとても格好いい