私は2017年の iMac で、VS Code を使って設計のメモを Markdown で書いています。構成やデータの流れも同じファイルに置きたくて、mermaid を使い始めました。
調べながら試して「この形が良さそうだ」というところに落ち着いたので、共有します。mermaid をこれから使う人向けの、基本の書き方と、私の iMac と VS Code での見方です。
1. mermaid とは
Markdown のコードブロックに書くと、そのまま図になる記法です。
こう書くと、
```mermaid
flowchart LR
A[入口] --> B[処理] --> C[出口]
```
こう出ます。
画像ファイルと比べた利点は3つです。
- 画像ファイルを作らなくていい。 図が Markdown の中に文字として入る
- 直すのが速い。 箱を1つ足すのは1行足すだけ
- 差分が見える。 git で「どこが変わったか」が行単位で分かる
Qiita・GitHub・VS Code は mermaid に対応しているので、貼るだけで図として表示されます。
2. 基本の書き方
箱と矢印
--> でつなぐだけです。名前だけ書くと、その名前が箱になります。
箱の中の文字を変えたいときは [ ] で囲みます。左側の A B は自分で付ける名前で、図には出ません。
箱の形
囲む記号で形が変わります。私は判断するところを { } の菱形にして、それ以外は四角のままにしています。
矢印の種類
--> が実線、==> が太い線、-.-> が点線です。私は「いつもの流れ」を実線、「例外のときだけ通る道」を点線にしています。
矢印に文字を付ける
| で挟みます。条件を書くところです。
箱をグループにする
subgraph で囲むと、枠が付いて名前が入ります。
⚠ end を書き忘れると図が丸ごと出なくなります。 エラーの場所も分かりにくいので、subgraph を書いたらその場で end も打っておくと楽です。
向き
flowchart の後ろの2文字が向きです。
| 書き方 | 向き |
|---|---|
flowchart LR |
左から右 |
flowchart TD |
上から下 |
flowchart RL |
右から左 |
flowchart BT |
下から上 |
⭐ 私は基本的に LR(左から右)を使っています。 縦向きは、箱が増えると下へ伸びて画面に収まらなくなるからです。⚠ Qiita に貼るときも、縦に長い図は下が切れることがあります。この記事の図が全部横向きなのはそのためです。
3. VS Code で見る
VS Code は、そのままでは mermaid を図として表示しません。拡張を1つ入れます。
拡張の検索で Markdown Preview Mermaid Support(作者 Matt Bierner)を入れてください。入れたら Markdown を開いて ⌘K を押してから V(Windows は Ctrl+K → V)でプレビューが右に出ます。
⭐ 左で1行足すと、右の図がすぐ描き直されます。 保存を待たずに反映されるので、箱の並びを試しながら書けます。
4. 箱が増えて線が絡んできたら
ここからが、私が調べて「これが良さそうだ」と思った部分です。
箱が5個くらいまでは、そのままでも読めます。ところが10個を超えたあたりから線が交差し始めて、どこからどこへつながっているのか目で追えなくなりました。
mermaid には並べ方を選ぶ設定があります。何も書かないと dagre というやり方で並びますが、elk に替えられます。図の先頭に4行足すだけです。
```mermaid
---
config:
layout: elk
---
flowchart LR
A[入口] --> B[処理]
B --> C[出口]
```
⚠ 足すのは flowchart の上です。 Qiita の記事の一番上にも --- で囲んだ部分がありますが、それとは別物で、mermaid のコードブロックの中に書きます。
私の図と同じ形(箱9個・線13本・グループ3つ)で比べたのが、この2枚です。⚠ 図の中の名前だけ例に置き換えています。
dagre では、マスタから一覧表へ向かう線が3か所で交差しています。 同じ mermaid の先頭に4行足しただけの図がこちらです。
交差は0になり、線は直角に折れて段がそろいました。 図の中身は1文字も変えていません。
ELK は Eclipse Layout Kernel という配置を計算するプログラムで、mermaid 11 から使えるようになりました。
⚠ elk の下にはもう1つ mergeEdges という設定がありますが、私は触っていません。 true にすると線が束ねられて見た目はすっきりするのですが、元の図に無いつながりが読めてしまいました(同じ経路に重ねて描くだけで、線が減るわけではないため)。書かなければ既定のままなので、そのままにしています。
5. ⚠ ただし VS Code のプレビューでは効きません
ここでつまずきました。
先頭に4行足しても、VS Code のプレビューでは図が何も変わりません。 エラーも警告も出ません。私は最初、自分の書き方を間違えたのだと思いました。
原因を切り分けるために、同じファイルに3つ並べて試しました。
| 試したこと | 結果 |
|---|---|
| ① 何も指定しない図 | 表示される(mermaid そのものは動いている) |
② config: theme: forest を足す |
箱が緑になる(先頭の config は届いている) |
③ config: layout: elk を足す |
何も変わらない |
②が効いて③が効かないので、「config が読まれていない」のではなく「layout だけが効いていない」と分かりました。
拡張の中を見ると ELK の部品はちゃんと入っています。それでも動きません。ELK は動かすのに Web Worker という機能を使うのですが、VS Code のプレビューの中では作れません。失敗すると mermaid はエラーを出さずに元の並べ方へ戻るという動作でした。
⚠ 失敗しても何も出ないので、動いていないことにすら気づけません。 Obsidian でも同じでした。
⚠ この Qiita のプレビューも同じです。 この記事に貼った4行入りのコードをそのまま Qiita に書いても、ELK では描かれません。
6. だから私はブラウザで見ています
ELK が効くのは、mermaid をブラウザが直接読み込んだときです。そこで、Markdown を渡すと図だけを抜き出して HTML にして開くスクリプトを作りました。
~/bin/mermaid_view.sh として保存します(~/bin が無ければ mkdir -p ~/bin で作ってください)。
#!/bin/sh
# Markdown の中の mermaid を ELK 配置の HTML にして開く
# sh mermaid_view.sh <入力ファイル> [出力HTML]
python3 - "$@" <<'PY'
import sys, os, re, html, subprocess
TEMPLATE = """<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>__TITLE__</title>
<style>
body{margin:0;padding:28px 24px 60px;background:#f8fafc;color:#0f172a;
font-family:-apple-system,BlinkMacSystemFont,"Hiragino Sans","Noto Sans JP",sans-serif;}
h1{font-size:17px;margin:0 0 22px;}
.fig{background:#fff;border:1px solid #e2e8f0;border-radius:12px;
padding:18px 20px 22px;margin:0 0 22px;overflow-x:auto;}
.fig h2{font-size:13px;color:#64748b;font-weight:600;margin:0 0 12px;}
.mermaid{display:flex;justify-content:center;min-height:60px;}
</style>
</head>
<body>
<h1>__TITLE__</h1>
__FIGURES__
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
import elkLayouts from 'https://cdn.jsdelivr.net/npm/@mermaid-js/layout-elk@0/dist/mermaid-layout-elk.esm.min.mjs';
mermaid.registerLayoutLoaders(elkLayouts);
mermaid.initialize({
startOnLoad: true,
layout: 'elk',
elk: { mergeEdges: false },
fontFamily: '-apple-system, "Hiragino Sans", "Noto Sans JP", sans-serif',
flowchart: { htmlLabels: true, nodeSpacing: 40, rankSpacing: 80 },
});
</script>
</body>
</html>
"""
if len(sys.argv) < 2:
print("使い方: sh mermaid_view.sh <入力ファイル> [出力HTML]", file=sys.stderr); sys.exit(1)
src = os.path.abspath(sys.argv[1])
if not os.path.exists(src):
print("入力が見つかりません: " + src, file=sys.stderr); sys.exit(1)
lines = open(src, encoding="utf-8").read().split("\n")
blocks, heading, i = [], "", 0
while i < len(lines):
line = lines[i]
if re.match(r"^\s*`{3,}\s*mermaid\s*$", line):
body, i = [], i + 1
while i < len(lines) and not re.match(r"^\s*`{3,}\s*$", lines[i]):
body.append(lines[i]); i += 1
blocks.append((heading, "\n".join(body).strip()))
elif re.match(r"^\s*`{3,}", line): # mermaid 以外のコードブロックは飛ばす
i += 1
while i < len(lines) and not re.match(r"^\s*`{3,}\s*$", lines[i]):
i += 1
else:
m = re.match(r"^(#{1,6})\s+(.*)$", line)
if m:
heading = m.group(2).strip()
i += 1
if not blocks:
print("mermaid のブロックが1つもありません: " + src, file=sys.stderr); sys.exit(2)
figs = []
for n, (head, body) in enumerate(blocks, 1):
label = html.escape(head) if head else "図 " + str(n)
figs.append('<div class="fig">\n <h2>' + label + '</h2>\n'
' <pre class="mermaid">' + html.escape(body) + '</pre>\n</div>')
title = os.path.splitext(os.path.basename(src))[0]
out = sys.argv[2] if len(sys.argv) > 2 else os.path.join(
os.path.dirname(src), title + "_図.html")
page = (TEMPLATE.replace("__TITLE__", html.escape(title))
.replace("__FIGURES__", "\n".join(figs)))
open(out, "w", encoding="utf-8").write(page)
print("図 " + str(len(blocks)) + " 枚 → " + out)
subprocess.run(["open", out], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
PY
打ち方はこれだけです。
sh ~/bin/mermaid_view.sh "設計メモ.md"
同じフォルダに 設計メモ_図.html ができて、ブラウザが開きます。
動き方はこうです。
- ファイルの中の mermaid を全部拾って、1枚の HTML に上から順に並べる(図が何枚あってもファイルは1つ)
- 各図の上には、その図より前にある直近の見出しが載る
- 文章・表・段落は載らない。 図だけを抜き出すスクリプトです
- 同じ名前で毎回上書きするので、Markdown を直して打ち直せば図も新しくなります
⚠ npm install は要りません。 mermaid 本体と ELK はネットから読み込みます。⛔ 逆に言うと、つながっていないと図が出ません。
⭐ このスクリプトの中の HTML で layout: 'elk' を指定しているので、Markdown 側に4行を書いていなくても ELK で並びます。 4章の4行は、VS Code や GitHub にそのまま貼りたいときのためのものです。
まとめ
| やりたいこと | どうするか |
|---|---|
| 図を Markdown に書く | ```mermaid のコードブロックに flowchart LR
|
| 判断するところを分ける |
{ } で菱形にする |
| 例外の道を分ける |
-.-> の点線にする |
| 箱をまとめる | subgraph 名前 ... end |
| VS Code で見る | 拡張 Markdown Preview Mermaid Support + ⌘K V |
| 線の交差を減らす | 先頭に config: layout: elk の4行 |
| その4行を効かせる | ⛔ VS Code では効かない。上のスクリプトでブラウザに出す |
⭐ まず動かすなら、2章の書き方だけで十分です。 私も最初は --> でつなぐだけでした。線が絡んで読めなくなってから、4章から先を調べ始めました。同じところで止まっている人の助けになれば。

