見出しアンカーは必要?長い記事の移動・共有で役立つ場面と増やしすぎるデメリット

AstroはMarkdown見出しへ自動でIDを付けるため、追加プラグインなしでもページ内アンカーを使えます。長い技術記事の目次や特定セクション共有で役立つ一方、見出し変更によるURL切れ、UIの増加、固定ヘッダーやコピー機能の注意点もあります。

執筆:ゆまラボ運営者

公開:
見出しアンカーは必要?長い記事の移動・共有で役立つ場面と増やしすぎるデメリット

長い技術記事を読んでいると、「この記事を見て」ではなく「この見出しのところを見て」と伝えたい場面がある。

URLが記事の先頭だけを指していると、共有された側はページを開いたあとに目次や本文から対象箇所を探す必要がある。

アンカーリンクがあると、

https://example.com/blog/article/#使う場面

のように、記事の中の特定セクションをURLで指定できる。

ゆまラボではすでに記事上部に目次があり、長い記事ほど見出し単位で移動する機会が増えている。現在のAstroではMarkdownの見出しへIDが自動で付くため、ページ内リンクの土台自体はすでにある。

追加を検討するなら、「アンカーリンクそのものを使えるようにする」というより、見出し横のリンクやURLコピーボタンを見せ、読者がその機能を使いやすくするかが論点になる。

AstroではMarkdown見出しにIDが自動で付く#

Astro公式ドキュメントでは、MarkdownとMDXの見出しにid属性が自動で付与される。

例えばMarkdownに、

## 使う場面

があれば、生成HTMLには見出しIDが入り、URL末尾へ#...を付けることでその位置へ移動できる。

Astroは見出しIDの生成にgithub-sluggerを使っている。Content Collectionsで記事をrender()した場合も、見出し情報には生成されたslugが含まれる。

そのため、単純なページ内リンクだけならJavaScriptは必要ない。

<a href="#使う場面">使う場面へ</a>

のような通常のリンクで動く。

ブラウザ側では#以降をfragment identifierとして扱う。MDNの説明では、このfragmentはサーバーへ送られず、ページを取得した後にブラウザが対象IDへ移動する。

目次のリンクからURLフラグメントを使って特定の見出しへ移動する概念図

※ 記事内の図は内容を整理するために作成した概念図です。各社の公式資料や実際の製品画面ではありません。

現在のゆまラボに目次があるなら、各項目から見出しへ移動する仕組みはこのIDをそのまま使える。

見出し横へ鎖アイコンを追加したり、「この見出しのURLをコピー」を付けたりする場合も、生成済みIDを再利用できる。

使いやすいのは長い記事と一部分だけ共有したい場面#

アンカーリンクが特に効くのは、本文全体を上から読まなくてもよい記事。

技術ブログではかなり該当する。

例えばエラー対応の記事に、

症状
原因
修正方法
確認方法

があるとする。

同僚やSNSで伝えたいのが「確認方法」だけなら、記事トップのURLを送るより、

/blog/example/#確認方法

を送った方が早い。

設定手順の記事でも同じ。

「この手順の3番だけ見てほしい」という用途では、見出しを直接開ける方が相手の探索が少なくなる。

ゆまラボのように1記事が長くなりやすく、目次も表示しているサイトでは、

目次
→ 読者が記事内を移動する

見出しアンカー
→ 記事外からその位置へ直接入る

という役割分担になる。

FAQや用語集のように、1ページの中へ複数の独立した回答を置くページとも相性がよい。

逆に、2~3見出ししかない短い記事では効果が小さい。記事先頭から対象箇所まで数秒で読めるなら、見出し横へボタンを増やす方が目立つ場合もある。

URLコピーまで付けるなら少し実装が増える#

見出し自体へ普通のアンカーリンクを付けるだけならHTMLで済む。

「クリックしたら、その見出しを含む完全なURLをクリップボードへコピーする」となると、Clipboard APIを使う形になる。

例えば処理の考え方は次の程度。

const url = new URL(window.location.href);
url.hash = headingId;

await navigator.clipboard.writeText(url.toString());

navigator.clipboard.writeText()は現在広く利用できるが、MDNではsecure context、つまりHTTPSで使うAPIとして案内されている。

bringain.comはHTTPSなので本番環境とは相性がよい。

ただし、コピー処理が失敗する可能性は残る。

そのため実装するなら、

見出しアンカーそのもの
→ 通常の<a href="#id">

URLコピーボタン
→ JavaScript + Clipboard API

を分けた方が扱いやすい。

コピーに失敗してもページ内リンクまで使えなくなる構成にはしない。

見出し横をクリックしたらURLのhashだけ変わり、そこからブラウザのアドレスバーをコピーできる状態でも最低限の目的は達成できる。

見出しを変更すると共有済みURLが古くなる#

デメリットで一番気になるのはここ。

Astroの見出しIDは見出しテキストから生成される。

例えば、

## 使うメリット

から生成されたIDを外部へ共有したあと、見出しを、

## アンカーリンクを使う利点

へ変更すると、生成IDも変わる可能性がある。

古いURLはページ自体にはアクセスできるが、該当IDがなくなれば期待した見出し位置へ移動できない。

ページの404にはならないので、普通のリンク切れより気付きにくい。

ゆまラボでは内部リンクの404をビルド時に確認する仕組みをすでに入れているが、その検査ではquery stringとhash fragmentを外し、ページ本体が存在するかを確認している。見出しIDの存在確認までは対象にしていない。

つまり、

/blog/example/#old-heading

/blog/example/が存在していれば、現在の内部リンクチェックは成功する。

実際の#old-headingが消えていても検出できない。

アンカーリンクを積極的に使うなら、これは運用上の弱点になる。

対処方法は大きく2つ。

1つは、公開後に見出し文言をむやみに変更しないこと。

もう1つは、将来アンカーリンクの利用が増えた段階で、内部リンクチェッカーへfragment IDの存在確認を追加すること。

最初からそこまで作る必要はないが、「通常リンクの404チェックでアンカー切れまで守られる」とは考えない方がよい。

同じ見出し名と日本語IDも確認しておきたい#

見出しIDを自動生成する場合、記事側でIDを毎回考えなくてよい。

その代わり、自動生成規則に依存する。

同じ見出しが複数回ある場合は、一意になるようIDへsuffixが付く。

記事へ後から同名見出しを追加したり、見出し順を変更したりすると、共有済みfragmentとの関係を確認した方がよい。

日本語見出しもアンカーにできる。

Astro公式の日本語ドキュメントでも、日本語見出しへ#はじめにのように直接リンクする例が載っている。

ブラウザやコピー先ではURLエンコードされた長い文字列として見えることがあるので、

#使う場面

が常にそのまま読みやすく表示されるとは限らない。

技術的には問題なくても、SNSやメールへ貼ったURLが長く見える点はデメリットになる。

このため「URLを短くしたいから全部英語IDへ手動変更する」という判断もできるが、そうすると今度はID管理が別作業になる。

ゆまラボではまずAstro標準IDを使い、問題が出てから個別対応する方が負担は少ない。

固定ヘッダーがあると見出しが隠れることがある#

ページ内リンクで対象見出しへ移動したとき、ブラウザは対象要素を画面上部へ寄せる。

サイト上部にposition: stickyや固定ヘッダーがあると、移動先の見出しがヘッダーの下へ隠れる場合がある。

これは機能としてリンクが壊れているわけではないので、実装後の確認で見落としやすい。

CSSでは対象見出しへ、

article :is(h2, h3) {
  scroll-margin-top: 6rem;
}

のように余白を指定できる。

MDNでもscroll-margin-topは固定ヘッダーがある場合の位置調整に利用できるとしている。

ゆまラボへ見出しアンカーUIを付けるなら、PCだけでなくスマホでも、

目次から移動
見出し横のアンカーから移動
外部から#fragment付きURLを直接開く

の3パターンを見る。

見出しタイトルが画面外やヘッダー裏へ入らないことを確認したい。

アンカーアイコンを全見出しへ出すと本文がうるさくなる#

機能として便利でも、見出しのたびに鎖アイコンや「URLコピー」を常時表示すると、記事の見え方は変わる。

特にスマホでは見出し幅が狭い。

長い日本語見出しの横へアイコンを固定すると、

見出しが不自然に改行される
アイコンだけ次の行へ落ちる
タップ領域が本文へ近づく

といった問題が出る。

技術記事で一番読ませたいのは見出し名なので、アンカーUIを目立たせすぎない方がよい。

実装候補としては、

PC
→ 見出しhover時だけ表示

スマホ
→ 小さく常時表示、または見出しタップとは別領域

目次
→ 従来どおりテキストリンク

のような方法がある。

ただしhoverだけにすると、タッチ端末では発見しにくい。

「常時表示かhoverか」に正解があるわけではない。

ゆまラボでは実装前後をスマホで見て、見出しの読みやすさを優先して決める方がよさそうだ。

短い記事まで一律に表示する必要もない。

ゆまラボでは追加する価値があるが、機能は小さくしたい#

現在のゆまラボは記事数が増え、1記事あたりの内容も長くなっている。

目次がすでにあり、Astro側の見出しIDも標準で生成される。

この状態なら、アンカーリンクを使うための土台を新しく作る必要はほとんどない。

追加するなら、

見出し横へ小さなリンク操作を追加

クリックで#fragmentへ移動

必要ならURLをコピー

程度でよい。

使いどころは、長い技術記事の一部分を共有するとき。

特に設定値、エラー対応、比較表、確認手順など、「記事全体ではなくこの節を見てほしい」と伝える場面では分かりやすい。

一方、導入すると見出しIDも公開URLの一部として扱うことになる。

見出し変更、同名見出し、固定ヘッダー、スマホ表示、コピー失敗、現在のリンクチェッカーがfragmentを検査しない点は確認対象になる。

アンカーリンク自体は小さな機能だが、共有したURLを長く残すなら見出し名も少し変更しにくくなる。

ゆまラボでは「全見出しを強く装飾する機能」ではなく、「必要なときにその節を共有できる小さな操作」として追加するのが合いそうだ。

参考#