Markdown リンクを理解したい

# Markdown リンクを理解したい

:::note info
本記事では、CommonMark に準拠したリンクについて解説します。

また、CommonMark に限らず GFM や footnote にも少し触れています。CommonMark にない記法に関しては見出しに “**†**” を付けています。
:::

:::note warn
筆者が CommonMark の説明ではよく分からなかった多く部分を独自に焼き直しています。そのため、CommonMark に存在しないエッジケースを生じさせている可能性があることに注意してください。
:::

Markdown におけるリンクは以下の 3 種類がある。

- 自動リンク (Autolinks)
- 手動リンク
    - 隣接型
    - 参照定義型

これらのリンクについて知っていきたい。

まず、本記事では、リンクを記述する上で重要な URI と URI スキームに関して略説を入れておきたい。

- **URI**

    “Uniform Resource Identifier” の略。URL よりも広い概念。

    本記事では URL と同義として利用するが、CommonMark では URI と呼称されていたため、そのまま利用。

- **URI スキーム**

    URL の先頭にある `http:` や `https:`、`mailto:` などのこと。100 種以上あるらしい。

    > [\# 公式登録のスキーム \- Uniform Resource Identifier - Wikipedia](https://ja.wikipedia.org/wiki/Uniform_Resource_Identifier#%E5%85%AC%E5%BC%8F%E7%99%BB%E9%8C%B2%E3%81%AE%E3%82%B9%E3%82%AD%E3%83%BC%E3%83%A0)

## ■ 自動リンク

CommonMark では、生の絶対 URI を文字列として解釈する。これを `<` \~ `>` で囲むことで URI を自動的にリンク化することが出来る。

```markdown
<https://www.example.com>
```

<https://www.example.com>

これは、次節以降で示す手動リンクの `[https://www.example.com](https://www.example.com)` と同じ結果を得ている。ただし、リンクタイトルを含めることは出来ない。

URI に以下のような文字が含まれる場合は、エンコードする必要がある。

- ASCII 制御文字以外の文字
- 半角スペース（`%20`）
- `<`、`>`

この自動リンクでは、必ずしも有効な URI のみがリンク化されるわけではない。これは URI スキームの解析が不十分だからのようだ。~~よく分からん~~

```markdown
<a+b+c:d>
```

<a+b+c:d>

また、自動リンクではメールアドレスを作成することも出来る。

```markdown
<example@email.com>
```

<example@email.com>

これは、次節以降で示す手動リンクの `[example@email.com](mailto:example@email.com)` と同じ結果を得ている。（`mailto:` はメールの URI スキームの 1 つ）

### ▽ 拡張自動リンク <sup>†</sup>

> [§ 6.9 Autolinks (extension)](https://github.github.com/gfm/#autolinks-extension- "GFM enables the autolink extension, where autolinks will be recognised in a greater number of conditions.")

GFM では、自動リンクをより拡張した拡張自動リンクが導入されている。これは URI を囲うことなく自動的に URI を検出しリンク化するものである。

ここでは仕様を詳細に追わないが、完全な URI でなくても自動的に補完してリンク化してくれる。

この拡張自動リンクから、リンクカードを作成するようにしているパーサも多くある。Qiita もそれに漏れない。

リンクカードとは：
- リンクに枠が囲われる
- 1 枚の画像を貼り付けたようになる

機能のことを指す。これを嫌う場合は、`<` \~ `>` で囲って自動リンクにすると良い。

```markdown
https://www.example.com
```

https://www.example.com

ただし、このリンクカードは他のブロックにネストされた中などでは機能せず、常に独立している必要があるようだ。（インデントは半角スペース 3 つまでが許容される）

## ■ 手動リンクの構造

隣接型リンクと参照定義型リンクは **表示テキスト部** と **URI アドレス部** に大別できる。

- **表示テキスト部**

    実際に表示されるテキストの部分。`[` \~ `]` に囲われる。このテキストにリンクが埋め込まれる。

- **URI アドレス部**

    埋め込まれる URI アドレスの部分。オプションとしてリンクタイトルを付随することが出来る。
    URI アドレス部は隣接型と参照定義型とで記法が異なる。

    - 隣接型では、URI アドレスが `(` \~ `)` に囲われる
    - 参照定義型では、ファイル内のどこかで `[label]: ` につづけて URI アドレス（とリンクタイトル）が定義される
        - この `[label]` によって、埋め込む URI アドレスを呼び出すことが出来る

各部を型ごとに例を示しておきたい。

```markdown
<!-- 隣接型リンク -->
                  URI アドレス部
                  ↓
                __________________________
[displayed text](URI/address "link title")
^^^^^^^^^^^^^^^^
  ↑
  表示テキスト部
```

```markdown
<!-- 参照定義型リンク -->
                  URI アドレス部（参照アドレス）
                  ↓
                _______
[displayed text][label]
^^^^^^^^^^^^^^^^
  ↑
  表示テキスト部

[label]: URI/address "link title"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ↑
  URI アドレス部（定義アドレス）
```

## ■ 表示テキスト部

表示テキストは `[` \~ `]` で囲まれる。この表示テキスト内では、`\` によってエスケープされていない `[`、`]` を含めることは出来ない。またこれらの `[`、`]` はペアでなければならない。

表示テキストはこの他のインライン表現と互い違いとなった場合、以下のような優先順位となる。

1. 行内コード、自動リンク、HTML タグ
1. 表示テキスト
1. 強調

すなわち、以下のような場合、表示テキストよりも行内コードが優先される。

```markdown
`[Example` Domain](https://www.example.com)
```

`[Example` Domain](https://www.example.com)

一方で、次のような場合は強調よりも表示テキストが優先される。

```markdown
**[Example** Domain](https://www.example.com)
```

**[Example** Domain](https://www.example.com)

## ■ URI アドレス部

URI アドレス部は “隣接型” と “参照定義型” の 2 つに大別される。

これらには共通して、URI アドレスについて次の仕様が適用されている。

- 改行されない
- フラグメント識別子、クエリを含めることが出来る
- 半角スペースが含まれる場合、`\` でエスケープされていない `<` \~ `>` で URI を囲うことで自動的に `%20` にエンコードされる
    ```markdown
    [displayed text](<URI address> "link title")
    ```

### ▽ 隣接型

隣接型リンクは以下のように記述される。

```markdown
                  URI アドレス部
                  ↓
                __________________________
[displayed text](URI/address "link title")
^^^^^^^^^^^^^^^^
  ↑
  表示テキスト部
```

隣接型リンクでは、
- 表示テキスト部と URI アドレス部は分割されない
- URI アドレス部の構成要素（`(`、URI アドレス、リンクタイトル、`)`）を半角スペースやタブ、改行で分割しても良い

```markdown
[Example Domain](
  https://www.example.com
  "This domain is for use in illustrative examples in documents.
  You may use this domain in literature without prior coordination or asking for permission."
)
```

[Example Domain](
  https://www.example.com
  "This domain is for use in illustrative examples in documents.
  You may use this domain in literature without prior coordination or asking for permission."
)

### ▽ 参照定義型

参照定義型リンクは以下のように記述される。

```markdown
                  URI アドレス部（参照アドレス）
                  ↓
                _______
[displayed text][label]
^^^^^^^^^^^^^^^^
  ↑
  表示テキスト部

[label]: URI/address "link title"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ↑
  URI アドレス部（定義アドレス）
```

本記事における参照定義型リンクで利用される定義アドレスは CommonMark では *Link reference definitions* と呼ばれる。

定義アドレスは以下のような仕様になっている。

- 定義アドレスは半角スペース 3 つまでのインデントが許容される
    - 2 行目以降は任意の数のインデントが許容される
- 定義された URI アドレスはドキュメント内で必ず使用されなくても良い
- `[label]:` と URI アドレスは少なくとも 1 つの半角スペースやタブ、改行が必要
- 定義アドレスの構成要素（`[label]:`、URI アドレス、リンクタイトル）は半角スペースやタブ、改行で分割しても良い
    ```markdown
    [example]:
      https://www.example.com
      "This domain is for use in illustrative examples in documents.
      You may use this domain in literature without prior coordination or asking for permission."
    ```

参照アドレスは以下のような仕様になっている。

- 同じ参照アドレスを複数回呼び出すことが可能
- `[label]` に関して
    - 同名が利用された場合、ファイルの先頭にあるラベル名が利用される
    - 1\~999 の文字が必要（半角スペースや改行は不可）
    - 大文字・小文字を区別しない (*case-insensitive*)
    - *Unicode case fold* される ([\# Case folding \-Character Model for the World Wide Web: String Matching][unicode-cf])
        - たとえば、`ß` と `ss` が同一視される

[unicode-cf]: https://www.w3.org/TR/charmod-norm/#dfn-case-folding

埋め込むリンクを示す参照アドレスには *full*、*collapse*、*shortcut* の 3 つのタイプがある。それぞれの記述方法を以下に示す。

- **full 参照リンク** [<sup>⧉</sup>][cm-full]

    ```markdown
    [displayed text][label]

    [label]: URI/address "link title"
    ```

    基本的な参照方法。表示テキスト部と参照アドレスとの間に半角スペースを含むことは出来ない。これは shortcut リンク参照との差別化点となっている。

- **collapse 参照リンク** [<sup>⧉</sup>][cm-collapse]

    ```markdown
    [label][]

    [label]: URI/address "link title"
    ```

    表示テキスト部に続く `[]` はラベル名を省略し、表示テキストがラベル名の `[label]` となっている。すなわち、`[label][label]` と同じ。
    これも shorcut リンク参照と差別化するため、表示テキスト部と参照アドレス半角スペースを含むことは出来ない。

- **shortcut 参照リンク** [<sup>⧉</sup>][cm-shortcut]

    ```markdown
    [label]

    [label]: URI/address "link title"
    ```

    表示テキスト部を省略し、`[label]` を表示テキストとした参照アドレス。

[cm-full]: https://spec.commonmark.org/0.30/#full-reference-link "full reference link for CommonMark spec"
[cm-collapse]: https://spec.commonmark.org/0.30/#collapsed-reference-link "collapse reference link for CommonMark spec"
[cm-shortcut]: https://spec.commonmark.org/0.30/#shortcut-reference-link "shortcut reference link for CommonMark spec"

shortcut 参照リンクがあるので、collapse 参照リンクが利用されるシーンはあまりないように思われる。

参照定義型は隣接型に比べ、「何度も同じアドレスを書く必要がない点」や「生のドキュメントがすっきりする点」がメリットとなっている。

### ▽ リンクタイトル

リンクタイトルはリンク先の補足情報。マウスカーソルを表示テキストにかざすと表示されるツールチップに対応している。これは必ず必要なものではないため、省略しても良い。

リンクタイトルは次の点に注意が必要になる。

- URI に続いて `"`、`'`、`(` \~ `)` で囲われる（ネストも可能）
- URI アドレスと少なくとも 1 つの半角スペース、タブまたは改行による区分けが必要
- 複数行に渡っても良いが、空白行を含んではならない
- 強調などの Markdown 記法は使えず、リテラルに解釈される

リンクタイトルを含む手動リンクは次のように書く。

```markdown
[Example Domain](https://www.example.com "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.")
```

[Example Domain](https://www.example.com "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.")

このリンクタイトルは複数行に渡っても問題ない。（本記事ではリンクタイトルがリンク内に含まれていることを明示的にするために、2 つの半角スペースでインデントしている。このインデントは無視される。）

```markdown
[Example Domain](https://www.example.com
  "This domain is for use in illustrative examples in documents.
  You may use this domain in literature without prior coordination or asking for permission."
)
```

[Example Domain](https://www.example.com
  "This domain is for use in illustrative examples in documents.
  You may use this domain in literature without prior coordination or asking for permission."
)

リンクタイトルを複数行で表現する場合、改行は改行として理解される。また、表示されるツールチップにインデントが含まれることがある。この辺りの仕様は CommonMark にない。

ただし、リンクタイトル内に空白行を含んではならない。

```markdown
[Example Domain](https://www.example.com
  "This domain is for use in illustrative examples in documents.

  You may use this domain in literature without prior coordination or asking for permission."
)
```

[Example Domain](https://www.example.com
  "This domain is for use in illustrative examples in documents.

  You may use this domain in literature without prior coordination or asking for permission."
)

## ■ 表示テキスト部内のリンク

手動リンクを手動リンクでネストすることは出来ない。ネストした場合、もっとも内側にあるリンクが有効になる。

```markdown
[Example Domain [Example Domain](https://www.example.com) ](https://www.example.com)

[Example Domain [Example Domain][example] ](https://www.example.com)

[example]: https://www.example.com
```

[Example Domain [Example Domain](https://www.example.com) ](https://www.example.com)

[Example Domain [Example Domain][example] ](https://www.example.com)

[example]: https://www.example.com

## ■ 手動リンクの類似記法

手動リンクに類似する記法がいくつかある。

### ▽ 画像表示

画像表示は手動リンクとほとんど変わらない。変更点は以下の通りである。

- 表示テキスト部の先頭に `!` を付ける (`![`)
- 表示テキストが **代替テキスト** として解釈される
    - `![displayed text]` ではなく `![alt text]`
- 代替テキストはプレーンテキストとして解釈される
- URI アドレスは **画像ファイルのアドレス** として解釈される（`<img>` タグの src 属性）

したがって、手動リンクと構造は同じだが以下のように表現される。

```markdown
![alt text](image/link "link title")

![alt text][label]

[label]: image/link "link title"
```

代替テキストは画像が表示されない場合に表示されるテキストになる。

```markdown
![Alternative text](non-existent/image/link "non-existent image link")
```

![Alternative text](non-existent/image/link "non-existent image link")

画像表示とリンクは入れ子にすることが出来る。そのため、画像にリンクを埋め込むとが出来る。

```markdown
[![Qiitan][qiitan]](https://qiita.com/ "Qiitaは、エンジニアに関する知識を記録・共有するためのサービスです。")

[qiitan]:
  https://cdn.qiita.com/assets/public/image-qiitan_for_login_modal-014e085d3e40a240e3fe8d61b70b29a9.png
  "Qiita のマスコットキャラクター “Qiitan”"
```

[![Qiitan][qiitan]](https://qiita.com/ "Qiitaは、エンジニアに関する知識を記録・共有するためのサービスです。")

[qiitan]:
  https://cdn.qiita.com/assets/public/image-qiitan_for_login_modal-014e085d3e40a240e3fe8d61b70b29a9.png
  "Qiita のマスコットキャラクター “Qiitan”"

リンクと画像の双方にリンクタイトルを含めることが出来るが、実際にツールチップとして表示されるリンクタイトルは画像側が優先されるようだ。

文末の `!` の後に手動リンクを続けたい場合には、`!` をエスケープする。

```markdown
\![Example Domain][notImage]

[notImage]: https://www.example.com "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission."
```

\![Example Domain][notImage]

[notImage]: https://www.example.com "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission."

### ▽ Markdown にネイティブなコメントアウト <sup>†</sup>

CommonMark では、Markdown にネイティブなコメントアウト記法を定義しておらず、HTML タグによるコメントアウトのみを規定している。

参照定義型リンクの定義リンクは表示されない。また、定義リンクは必ず参照する必要がない。これをコメントアウトとして利用することが出来る。ただし、リンクタイトル内をコメントアウトとしているため、空白行を含めることは出来ない。

```markdown
↓

[commentout]: <> "ここはコメントアウトのように非表示になる"

↑
```

↓

[commentout]: <> "ここはコメントアウトのように非表示になる"

↑

### ▽ 見出しへのアンカーリンク <sup>†</sup>

見出しへのアンカーリンクを作成することが出来る場合がある。（CommonMark では見出しに id 属性を与えていない）

ページ内の特定の見出しに移動するリンクを作成するには、手動リンクを使って以下のようにする。隣接型、参照定義型の両方を用いることが出来る。

```markdown
[Heading Title](#heading-title)

[Heading Title][head]

[head]: #heading-title "Heading title"
```

### ▽ footnote との衝突 <sup>†</sup>

Markdown における footnote について簡単にまとめておきたい。

- PHP Markdown Extra に由来している [<sup>⧉</sup>][phpMdEx-footnote]
- 記法は以下のようになっている
    ```markdown
    [^label]

    [^label]: ここは footnote の内容です。
    ```

[phpMdEx-footnote]: https://michelf.ca/projects/php-markdown/extra/#footnotes

記法を見れば明らかなように、shortcut 参照定義型リンクと同型の記法をしている。ただし、ラベル名が `^` から始まっていることに注意が必要。

このため、`^` から始まるラベル名を使用した参照定義型リンクでは、footnote との違いを記法から理解することが出来なくなる。（CommonMark の Link reference definitions では、`[label]` の先頭に `^` を付けてはいけない規則はない）

実際、footnote のないパーサで以下のような脚注を作成しても、参照定義型リンクに解釈される。

```markdown
ここはパラグラフです。[^footnote]

[^footnote]: ここは footnote です。Link reference definition ではありません……
```

:::note info
footnote との衝突を避けるため、参照定義型リンクのラベルは `^` から開始しない。
:::

# 参考

- [CommonMark Spec](https://spec.commonmark.org/0.30/)
    - [§ 4.7 Link reference definitions](https://spec.commonmark.org/0.30/#link-reference-definitions)
    - [§ 6.3 Links](https://spec.commonmark.org/0.30/#links)
    - [§ 6.4 Images](https://spec.commonmark.org/0.30/#images)
    - [§ 6.5 Autolinks](https://spec.commonmark.org/0.30/#autolinks)
- [#Footnotes \- PHP Markdown Extra](https://michelf.ca/projects/php-markdown/extra/#footnotes)

# 余談

Markdown リンクを説明する記事では、多く “インラインリンク” と “参照定義リンク” と呼称している。しかし、CommonMark には § 4.7 Link reference definitions が表示されるリンクそのものを指さず、リンクを定義する部分（本記事で言う “定義アドレス”）のみの仕様が記述されている。実際、リンクそのものは常にインラインであり、インラインとインライン以外（参照定義リンク）のような区別はおかしなように感じた。

このような経緯から、表示テキスト部と URI アドレス部に分割し、URI アドレス部が隣接するか参照定義するかで区別した。

また、単に “インラインリンク” と呼称する場合、直リンク [<sup>[Wikipedia]</sup>][wiki-inlineLinking-ja] の意味と解釈される場合 [^inlineLink] がある。一方で、CommonMark では [Inline link][inline-link] と呼んでいるものの、英語圏では直リンクのことを Inline linking [<sup>[Wikipedia]</sup>][wiki-inlineLinking] や Hotlinking と呼称されるため、英語圏では呼び分け上手くできているようだ。日本語では呼び分けが出来ていないため、本記事では別名を独自に定義した。

[^inlineLink]: 実際、Google で ` インラインリンク ` と検索すると、直リンクの意味で著作権関連の記事が表示される。

[wiki-inlineLinking-ja]: https://ja.wikipedia.org/wiki/%E7%9B%B4%E3%83%AA%E3%83%B3%E3%82%AF "直リンク（じかリンク、ちょくリンク）とは、インターネットの WWW で公開されている画像などのメディアファイルの URL を参照し、インラインで表示する形態で別のウェブサイトにあるウェブページに貼り付けたり、リンクを貼ったりすることである。直リンとも呼ばれる。"
[inline-link]: https://spec.commonmark.org/0.30/#inline-link "CommonMark spec"
[wiki-inlineLinking]: https://en.wikipedia.org/wiki/Inline_linking "Inline linking (also known as hotlinking, leeching, piggy-backing, direct linking, offsite image grabs) is the use of a linked object, often an image, on one site by a web page belonging to a second site. One site is said to have an inline link to the other site where the object is located."

URI アドレスのいくつかの文字に対するエスケープに関して、本記事では説明が端折られてる。そのため、詳細に知りたい人は CommonMark を参照してほしい。

本当は見出しのアンカーリンクに関する記事を書こうとしたのに、リンクに関する記事を書くことになっていた。ふしぎ。

## 拡張自動リンクの回避

:::note info
自動リンクの回避について、以下の記事により詳しくした。

[URL を自動リンクさせずに表示させたい - Qiita](https://qiita.com/Yarakashi_Kikohshi/items/a8241f90997f3781a199)
:::

拡張自動リンクでは URI アドレスを自動的にリンク化する。これを回避して文字列として表示させたい場合、次のようにコードなどに含めると良い。

````markdown
```
https://www.example.com
```

`https://www.example.com`
````

```
https://www.example.com
```

`https://www.example.com`

<!--
コピーする際に面倒にはなるが、ゼロ幅スペースの HTML エンティティ参照 (`&#8203;`) を URI アドレスの先頭に置くと、リンク化を防ぐことが出来る場合がある。

```markdown
&#8203;https://www.example.com
```

&#8203;https://www.example.com

Qiita では上手くリンクを回避出来ていない。
-->

# 追記

- 2022/11/19: CommonMark 以外の Markdown 記法が多く含まれているため CommonMark ではないと判断し、タイトルとタグを修正しました。余談の節でインラインリンクについて追記。
- 2022/12/15: 拡張自動リンクについての記事のリンクを追加。画像の追加、軽微修正。