一言で言うと
Markdownってのは、シンプルな記法でプレーンテキストに書式を追加できる軽量マークアップ言語のこと。書いたテキストは、あとで構造的に正しいHTMLに変換されるんだ。
解決する課題
ウェブの黎明期(2000年代初頭)に話を戻そう。ブログ記事やコメントを書こうと思ったら、イケてない選択肢が2つしかなかった。1つは生のHTMLを書くこと。これは山括弧と閉じタグの祭り(<p><strong><em>Ugh.</em></strong></p>)だった。もう1つは、Microsoft Wordや初期のブログプラットフォームにあったような「見たまま(WYSIWYG)」のリッチテキストエディタを使うことだ。
手でHTMLを書くのは面倒だし、間違いやすいし、ソーステキストがまるで機械がゲロを吐いたみたいに見える。読むのも大変だし、素早く書くのはもっと大変だ。一方、WYSIWYGエディタは親しみやすいインターフェースを謳っていたけど、裏では独自仕様で肥大化した、時には完全にぶっ壊れたHTMLの悪夢のようなスープを生成していることが多かった。エディタ間でテキストをコピペしようものなら、大惨事間違いなし。おまけに、コンテンツは簡単にはバージョン管理もできなければ、スクリプトで処理することもできないフォーマットに閉じ込められていた。
そんな世界で、2004年にMarkdownは生まれた。ライターのJohn Gruberが、故Aaron Swartzからの意見も取り入れながら作ったMarkdownの目標は、シンプルかつ brilliant だった。それは、テキストをフォーマットするための記法を、生のプレーンテキストの状態でも人間にとって可能な限り読みやすく作る、というものだ。
メールやプレーンテキストのドキュメントで人々がすでに理解している慣習を使って書けるようにしよう、というアイデアだった。単語をアスタリスクで囲んで*強調*する?数字とピリオドで1. リスト項目を作る?理にかなってるよね。Markdownは、HTMLの儀式やWYSIWYGエディタのカオスなしに、ウェブ用のテキストをフォーマットしたいという問題を解決する。まさに完璧な中間地点。人間が読みやすいソースで、機械が読みやすい構造なんだ。
内部の仕組み
要するに、Markdownプロセッサは翻訳機なんだ。君が書いたエレガントでシンプルなMarkdownテキストを入力として受け取り、堅牢でクリーンなHTMLを出力として吐き出す。この翻訳プロセスは、コンパイラにおける古典的な2ステップ、つまり『パース』と『レンダリング』から成る。
パーサーの華麗なる2ステップ
Markdownのパーサーは、超細かいけど親切なロボットみたいなものだと考えてみてほしい。家を建てる前に、まずテキストを読んで設計図を作るんだ。
パースとAST(抽象構文木): まず、パーサーはテキストをスキャンして、Markdownの構文を構成する特殊文字やパターンを特定する。単純な検索と置換をするだけじゃない。代わりに、**抽象構文木(Abstract Syntax Tree, AST)**を構築するんだ。ASTは、ドキュメントの論理構造を表すツリー状のデータ構造だ。
#で始まる行はHeadingノードになる。テキストの塊はParagraphノードになる。**で囲まれたテキストは、その段落の中の子要素としてStrong(太字)ノードになる。ASTは、リンクを含むリスト項目、そのリンクがさらに太字のテキストを含む、といった入れ子構造を理解する。いわば、ドキュメントの骨格だね。レンダリング(またはコンパイル): ASTが構築されると、レンダラはASTをノードからノードへと辿り、各ノードを対応するHTMLタグに変換していく。レベル1の
Headingノードは<h1>...</h1>になる。Paragraphノードは<p>...</p>に。Strongノードは<strong>...</strong>になる。構造化されたツリーから処理を行うので、生成されるHTMLは整形されていて、意味的にも正しいものになる。閉じ忘れたタグや奇妙な入れ子構造は生まれない。
Markdownと同期するWYSIWYGエディタは、これをリアルタイムで行っているだけなんだ。君が## My Headerと入力すると、パーサーがHeading (level 2)ノードを作成し、レンダラが即座に<h2>My Header</h2>を生成して「プレビュー」や「リッチテキスト」ペインに表示する。君がリッチテキストビューで「太字」ボタンをクリックすると、エディタはASTを修正し、逆方向に作業して生のMarkdownテキストに**文字を挿入する。
記法マッピング:記号からタグへ
Markdownのすごいところは、シンプルな記号が予測可能な形でHTML要素に対応付けられていることだ。ルールは何十もあるけど、ここではその中でも代表的なものをいくつか紹介しよう。
| Markdown記法 | 生成されるHTML | 表示例 |
|---|---|---|
# 見出し |
<h1>見出し</h1> |
見出し |
## サブ見出し |
<h2>サブ見出し</h2> |
サブ見出し |
**太字テキスト** |
<strong>太字テキスト</strong> |
太字テキスト |
*斜体テキスト* |
<em>斜体テキスト</em> |
斜体テキスト |
[FlowingDev](https://flowing.dev) |
<a href="https://flowing.dev">FlowingDev</a> |
FlowingDev |
`inline_code()` |
<code>inline_code()</code> |
inline_code() |
--- |
<hr> |
フレーバーと拡張機能(GFM!)
Gruberによるオリジナルの仕様は少し曖昧な部分があり、それが実装によって微妙な違いを生むことになった。このMarkdownの「フレーバー化」はバグではなく、むしろ特徴となった。その中でも圧倒的に主流なのが、**GitHub Flavored Markdown (GFM)**だ。
GFMは、今では多くの開発者にとって標準と見なされている、QoL(クオリティ・オブ・ライフ)を向上させるいくつかの機能を追加した。
- テーブル: パイプ
|とハイフン-を使ってテーブルを作成する方法。 - フェンス付きコードブロック: トリプルバッククオート (
) を使ってコードブロックを定義する。多くの場合、言語固有のシンタックスハイライト(例: `js `)も可能。これは元の「4つのスペースでインデントする」ルールからの大きな改善だった。 - 取り消し線: ダブルチルダ(
~~削除されたテキスト~~)を使ってテキストに取り消し線を引く。 - タスクリスト:
[ ]や[x]を使ってリスト内にチェックボックスを作成する。
実質的に、最近のMarkdownエディタのほとんどはGFMエディタだと言える。
実世界でのエピソード
プロジェクトを救ったREADME
若手開発者のマリアは、あるレガシープロジェクトに配属された。コードベースはコメントが一切ない、ぐちゃぐちゃに絡まった代物だった。パニックに陥りかけたその時、彼女はREADME.mdを見つけた。最近退職したばかりのシニア開発者は、Markdownの伝道師だったのだ。そのREADMEは、芸術品とも呼べるものだった。## セットアップ、## テストの実行、## デプロイといった見出しが明確に付けられていた。セットアップの項目では、番号付きリストが手順を一つ一つ説明してくれる。重要なコマンドは、きれいでコピペ可能なコードブロックにまとめられていた。リンクは社内Wikiや依存ライブラリのドキュメントに直接つながっていた。1週間はかかりそうなイライラの考古学調査になるはずが、わずか2時間のセットアップ作業で済んだのだ。
ここでの教訓: ドキュメントにおけるMarkdownは、単に見栄えを良くするためだけのものではない。それは知識を伝えるための強力なツールであり、開発者のオンボーディング体験を成功させるか失敗させるかを左右する力を持っているということだ。
ダサいCMSを捨てたブロガー
アレックスは技術的な深掘り記事を書くのが好きだったが、自分のブログのコンテンツ管理システム(CMS)が大嫌いだった。ウェブエディタは遅く、フォーマットは常に格闘の連続、コードスニペットの貼り付けはエスケープ文字とレイアウト崩れの悪夢だった。ある日、静的サイトジェネレータと「GitベースのCMS」というワークフローに出会う。自分のマシン上のシンプルなテキストエディタで、Markdownを使って記事が書けるようになった。オフラインでも、飛行機の中でも、どこでも書ける。Gitを使って、すべての記事のすべてのバージョンを追跡した。git push一発で、新しい記事が自動的にビルドされ、デプロイされるようになった。
ここでの教訓: Markdownは、コンテンツをプレゼンテーション層から切り離してくれる。ポータブルで将来性のあるフォーマットで自分の作品の所有権を保てるようになり、コードを管理するのと同じツールで管理できるようになるのだ。
意図が伝わるプルリクエスト
ある分散チームで、開発者が大きなロジック変更を含むプルリクエストを提出した。彼は、一行だけの説明で済ませず、10分かけてMarkdownで詳細なサマリーを書いた。箇条書きで変更点をリストアップし、inline_codeで特定の関数名に言及し、「変更前と変更後」のセクションでは2つの異なるdiffコードブロックを使って動作の正確な変化を示した。レビュアーは、単に何が変わったかだけでなく、その変更の理由を即座に理解できた。長く混乱したやり取りをすることなく、数分で自信を持って承認することができたのだ。
ここでの教訓: Markdownは、開発者にとって効果的な非同期コミュニケーションの言語である。よくフォーマットされたコメント、Issue、プルリクエストの説明は、何時間もの確認作業を節約し、誤解を減らす。
よくある間違いと落とし穴
- 空行を忘れる。 見出し、リスト、コードブロック、引用ブロックなどのブロックレベル要素は、前後の段落と空行で区切る必要がある。これを忘れると、パーサーが予期しない形で要素を合体させてしまうことがある。
- リストのインデントが不揃い。 入れ子になったリストを作るには、サブリストをインデントする必要がある。標準は半角スペース4つかタブ1つ。スペース2つや3つだと、一部のパーサーでは動くかもしれないが他では壊れたり、最悪の場合、リスト項目が意図せずコードブロックになってしまったりする。
- 改行が必ずしも
<br>タグになるとは限らない。 Enterキーを1回押すだけでは、通常、強制的な改行(<br>)にはならない。ほとんどのフレーバーでは、改行の前に半角スペースを2つ入れる必要がある。そうしないと、パーサーは行を連結して1つの段落にしてしまう。 - 意図せずフォーマットが適用されてしまう。 「ソーダを24パック買った」と書こうとすると、誤って「ソーダを24パック買った」と表示されてしまうかもしれない。
*、_、#のような特殊文字を文字通りに使いたい場合は、バックスラッシュでエスケープする必要がある:\*、\_、\#。 - URLとリンクタイトルの構文。 リンク
[text](url "title")や画像の構文は細かい。よくある間違いは、丸括弧と角括弧を入れ違えたり、画像を挿入したいのに!を忘れてただのリンクになってしまったりすることだ。
なぜ知っておくべきか
開発者として何かを書くなら、Markdownは避けて通れない。以下の用途でデフォルトの言語となっている。
- ドキュメンテーション:
README.mdファイルは、GitHub、GitLab、Bitbucket上のほぼすべてのプロジェクトの玄関口だ。 - コンテンツ作成: Hugo、Jekyll、Next.js、Eleventyなどの静的サイトジェネレータはすべて、主要なコンテンツフォーマットとしてMarkdownを使用している。
- コラボレーション: JiraやTrelloからSlack、Discord、Notionに至るまで、多くのツールがコメントや説明のフォーマットにMarkdown(またはその亜種)を採用している。
Markdownの学習は、少ない労力で大きな見返りが得られるスキルだ。人間と機械の両方が読める、クリーンで構造化された、ポータブルなテキストを書く力を与えてくれる。それはテキスト界のスイスアーミーナイフのようなもの。シンプルで、多機能で、あらゆる場面で信じられないほど役に立つ。
さらに深く知るには
- The original Markdown spec by John Gruber. すべてはここから始まった歴史的ドキュメント。
- The CommonMark Spec: Markdownの仕様を厳密に定義し、曖昧さをなくすための巨大なコミュニティの成果。最近のパーサーのほとんどはCommonMark準拠を目指している。
- GitHub Flavored Markdown (GFM) Spec: 最も人気のあるMarkdownフレーバーの公式仕様。テーブルやタスクリストなどの拡張機能が詳述されている。
- MDN Docs: Mastering Markdown: Mozilla Developer Networkによる、ドキュメンテーションでMarkdownを使うための実践的なガイド。(※訳注:日本語版は「MDN での執筆作業のガイドライン > Markdown ガイド」)
- Wikipedia: Markdown: Markdownの歴史、フレーバー、そして普及状況に関する包括的な概要。(※訳注:日本語版Wikipedia)