zfb
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

見出しリンク

すべての見出しにスラッグベースの id 属性とアンカーリンクを自動的に付与する。

HeadingLinksPlugin は常に有効です。すべての <h2><h6> をスラッグ化し、 読者が任意のセクションへのディープリンクをコピーできるよう、自己参照の アンカーリンクを注入します。

挙動

各見出しに対して、プラグインは次を行います:

  1. 見出しテキストからスラッグを計算する: 小文字化し、固定の ASCII 記号セットを 取り除き、空白を単一の - に折りたたむ。これは github-slugger の アルゴリズムであり、バイト単位で互換ではありません — 下記の注記を参照。

  2. 同一ドキュメント内で繰り返されるスラッグを、カウンターを付加することで 重複排除する(overviewoverview-1overview-2、…)。これは github-slugger 自体の番号付けよりも単純なベースごとのカウンターです。 github-slugger は衝突を考慮しており、既に別の見出しの見出しテキスト そのものが使っているサフィックスをスキップしますが、zfb のカウンターは そのケースをチェックしません。

  3. <h*> 要素に id 属性を設定する。

  4. 見出しの 最後の子 として、空の <a href="#slug" class="hash-link" aria-label="…"> を付加する。見出しテキストは包まれずに残ります。表示される # のグリフは CSS の ::after で描画されるため、アンカー本体は空のままになり、見出しテキストの 抽出(例: TOC 用)がクリーンに保たれます。

github-slugger とは互換ではありません

上記のスラッグ計算ステップ(1)は、見た目が似ていても npm の github-sluggerとは 互換ではありません。主な相違点: ストリップ対象の記号は削除されるの ではなく - セパレーターに置き換えられます — "a,b" はここでは "a-b" に なりますが、github-slugger では "ab" になります。固定の ASCII 記号セット の外にある Unicode の文字・数字・記号・句読点(CJK、かな、ハングル、全角 記号、絵文字)は、大文字小文字が適用される場合は小文字化されつつ、そのまま 通過します — これが日本語コンテンツの全角括弧を含む見出しでアンカーの 不具合を招いたことがあります。

上記の見出し ID アルゴリズムと、@takazudo/zfb/slugify として公開されているslugify() 関数(ソース: packages/zfb/src/slugify.ts)は、名前から連想され がちな「まったく無関係な 2 つのスラッグ生成器」ではなく同一のアルゴリズムで すが、実装は別々です: 見出し ID はcrates/zfb-content/src/plugins/heading_links.rs の Rust 版 slugify()から生成され、公開 API は独立した TypeScript 移植版です。共有フィクスチャ (crates/zfb-content/tests/fixtures/slugify-parity.json)は両者が現時点で 同じ出力を生成することをテストしているだけで、単一の実装であることを意味 しません。

## Introduction

## Introduction

次を生成します:

<h2 id="introduction">Introduction<a href="#introduction" class="hash-link" aria-label="Direct link to Introduction"></a></h2>
<h2 id="introduction-1">Introduction<a href="#introduction-1" class="hash-link" aria-label="Direct link to Introduction"></a></h2>

設定

プラグイン自体は常にオンです。ID 戦略markdown.features.headingIds で設定可能です:

// zfb.config.ts
export default {
  markdown: {
    features: {
      headingIds: { strategy: "hierarchical" },
    },
  },
};

strategy: "flat"(デフォルト)

上で説明した挙動です。h2h6 で共有される 1 つの重複排除カウンターを伴う github-slugger 風のスラッグです(上記の注記を参照)。headingIds を完全に 省略すると、この方式が保たれます。

strategy: "hierarchical"

各見出しの ID には、その祖先のチェーンが - で連結されて接頭辞として付きます:

## Foo

### Moo

#### Mew

(フラットな foomoomew の代わりに)id="foo"id="foo-moo"id="foo-moo-mew" を生成します。見出し内のハッシュリンクアンカー、 headings エクスポート、TOC エクスポートリンク検証 はすべて、 同じ ID に従います。

詳細:

  • 完全なパスが重複した場合も、重複排除カウンターが付きます(a-ba-b-1)。

  • 重複排除された親は、その 最終的な ID を子に提供します: 2 番目の ## Foofoo-1 になるため、その ### Barfoo-1-bar になります。

  • 階層的なアンカーは見出しのアウトラインから再構築でき、URL が長くなる代償と 引き換えに、フラットなスラッグよりはるかに衝突しにくくなります。

Warning

戦略を切り替えることは アンカーを壊します: 入れ子の見出しへの既存の ディープリンク(#moo)は、ID が #foo-moo になると解決されなくなります。

順序に関する注意

HeadingLinksPlugin は、hast フェーズで 最初に 実行されます。安定した 見出しの id 値に依存するプラグイン — TocPlugin(オプトインの 見出しマーカー TOC)や TocExportPlugin(オプトインの TOC エクスポート)など — は、 その後に実行される必要があります。

関連項目

Revision History

作成更新