VFMの紹介(MarkdownでVivliostyle入門 中編その2)

11 min read読了の目安(約10200字

この記事は Markdown Advent Calendar 2020 の15日目です。

この記事は4つの記事で構成されています。(注意:中編が膨れ上がってしまったので、2つに分割しています)


Vivliostyle Flavored Markdown(VFM)は、GitHub Flavored Markdown(GFM)を拡張したMarkdown方言です。

markdown には各種の方言がありますが、その中でもっとも有力なのが GFM (GitHub Flavored Markdown) です。ただし、これは技術ドキュメント向けに工夫された記法なので、日本語書籍向けの記法を追加したのが VFM (Vivliostyle Flavored Markdown) です。

つまり、VFM は GFM の上位互換です。見出しなどよく使う記法は GFM のままですから、慣れた人ならあまり苦労せずに使い始めることができるでしょう。

Create Book で同人誌を作ろう!

結論からいえば、Create Book で同人誌を作ろう!に記法がひととおり載ってます。またVFMの仕様については、下記に載っています。

以下、Create Book で同人誌を作ろう!からいくつか引用(一部改変)します。

GFMの記法

VFMには「GFMの記法」と「GFMを拡張する記法」(VFM独自の記法)の2つに大きく分類されます。

ただし「GFMの記法」の中にも、さらに3つがあります。

  1. GitHub Flavored Markdown Spec(GFM Spec)に準拠したMarkdown記法
  2. GitHubで実装されているMarkdown記法
    • 絵文字、メンションなど
  3. GFM Spec以前のGFM(いまは考えなくてもよい)

たとえば絵文字記法はGitHubで実装された記法ですが、GFM Specにはありません。筆者の大まかな印象としては、VFMで継承されているGFMは「GFM Specで対応している記法」が中心となっているようです。上記の引用で「VFM は GFM の上位互換です」とありますが、実際には「VFM (Spec) は GFM Spec の上位互換です」という方が近いでしょう(実装の話は最後に軽く触れます)。

以下、GFMの記法からいくつか抜粋してみます。

段落と改行

VFMの改行はGFMと同様に強制改行(hard line break)です。つまりMarkdown原稿上の改行1つ(Enterキー)がそのままPDF出力の改行(<br>)として反映されます

明示的に強制改行をしたい場合は、スペース2つ(␣␣)またはバックスラッシュ(\)が利用できます。

Markdown記法:

吾輩は猫である。名前はまだ無い。

どこで生れたかとんと見当がつかぬ。
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。
吾輩はここで始めて人間というものを見た。

しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。この書生というのは時々我々を捕えて煮て食うという話である。しかしその当時は何という考もなかったから別段恐しいとも思わなかった。

ただ彼の掌に載せられて \
スーと持ち上げられた時 \
何だかフワフワした感じ \
があったばかりである。

表示例:

段落と改行

見出し

# レベル1見出し
## レベル2見出し
### レベル3見出し
### レベル4見出し

リスト(順序なし)

- リスト
    - リストの入れ子
        - 入れ子の入れ子1
        - 入れ子の入れ子2

リスト(順序あり)

1. 番号が付いているリスト
    1. 入れ子
        1. 入れ子の入れ子1
        2. 入れ子の入れ子2

リンク

[テキスト](URL)

URLをそのまま入力すれば、クリッカブルなリンクとして表示されます。

https://vivliostyle.org/ja/

強調

**強調されたテキスト**

水平線

---

HTML上では<hr>要素に変換されます。

タスクリスト

- [x] りんご
- [ ] いちご
- [ ] みかん

インラインコード、コードブロック

インラインコード:

`code`

コードブロック:

```javascript
function main() {}
```

コードブロックは、プログラミング言語名の指定およびキャプションを付けられます。

```javascript:app.js
function main() {}
```

```javascript title=app.js
function main() {}
```

上記の場合、キャプションは「app.js」となります。プログラミング言語名はPrismに対応するものが利用できます。

Raw HTML(HTMLの埋め込み)

GFMに限らず、オリジナルのMarkdown(John Gruber)からの有名な仕様として「HTMLコードはそのままHTMLコードとして出力する」というものがあります。後述の「GFMを拡張する記法」でも、この性質を利用した記法がいくつか存在します。

たとえばMarkdown原稿にて次のように書けば、Vivliostyle側で同じHTMLコードを受け取って処理します。

※ 例はVivliostyle Flavored Markdown: Working Draftより引用

Markdown記法:

<div class="custom">
  <p>Hey</p>
</div>

HTML:

<div class="custom">
  <p>Hey</p>
</div>

また「HTMLの中に埋め込まれたMarkdown記法」は、HTMLに変換されます。

Markdown記法:

<div class="custom">

# Heading

</div>

HTML:

<div class="custom">
  <h1>Heading</h1>
</div>

注意:絵文字は使えない

GFMにおいて人気の絵文字記法ですが、Create Bookではサポートされません[1]

GFMを拡張する記法

VFMには「VFM共通の記法」と「テーマに依存する記法」があるので注意が必要です。

ルビ(VFM共通)

記法:

{親文字|ルビ}

VFMでの記述:

# {吾輩|わがはい}は猫である。

{吾輩|わがはい}は猫である。名前はまだ無い。

表示例:

ルビ

画像のサイズとキャプション(VFM共通)

記法:

![キャプション](./image.png){width=nnn}
  • 画像ファイルは丸括弧( )内に相対パスで指定します
  • nnn は数値(単位は px 、単位を省略して記述)
  • width (幅) の他に height (高さ) も使えます。

なお上記の例で キャプション と書かれている部分は、キャプション扱いとなります。キャプションは画像の下に表示されます(<figcaption>要素が付きます)。

VFMでの記述:

![VFMならキャプションも書けます。画像のサイズは幅1500pxです。](./fig-1.jpeg){width=1500}

HTMLへの変換結果:

<figure>
  <img src="./fig-1.jpeg" alt="VFMならキャプションも書けます。画像のサイズは幅1500pxです。" width="1500">
  <figcaption>VFMならキャプションも書けます。画像のサイズは幅1500pxです。</figcaption>
</figure>

VFMにおける「注」について

VFMで使える「注」は2つあります。

  • 後注(こうちゅう):各章の後部にまとめて述べる注記
    • VFMの実装では利用可能[2]
    • 例1:[^1](後注参照)、[^1]: foo(後注本体)
    • 例2:foo^[hoge]bar(インライン形式の後注)
  • 脚注:本文(ページ)の下につける注記
    • VFMの標準的な記法ではない
    • テーマパッケージ @vivliostyle/theme-techbook の記法
    • 例:<span class="footnote">foo</span>

後注(VFM共通)

後注は、各章の後部にまとめて出力されるタイプの注です。VFM共通で使えます。

ただし次の注意点があります。

  • 後注は章の最後に出力される(ページ直下に出ない
  • 章を区切るためには vivliostyle.config.js の entry で章を区切る必要がある
    • 1つのファイル(例:manuscript.md)の中でトップレベルの見出し(#)を複数立てても、「章の区切り」とはならないので注意

具体的には、次の準備をします。

  • 章ごとにファイルを用意する(例:chap1.md、chap2.md)
  • vivliostyle.config.js の entry に記述する

ファイルの例を示します。計2ページのためわかりにくいですが、第2章にあたる「吾輩は猫である。」の手前のページ(つまり1ページ目)に後注があります。

※ 下記の例では脚注の例も入れています。脚注はtheme-techbookのみです。

chap1.md
# 後注と脚注の例

これは後注[^1]の例です。インラインで後注^[これも章の後ろに表示される]もできます。

[^1]: 各章の後部にまとめて出力されるタイプの注

こちらは脚注<span class="footnote">ページ直下に表示される</span>です。
chap2.md
# {吾輩|わがはい}は猫である。

{吾輩|わがはい}は猫である。名前はまだ無い。
vivliostyle.config.js
module.exports = {
  // (中略)
  entry: [
    'chap1.md',         // 追加する
    'chap2.md',         // 追加する
    // 'manuscript.md'  ← コメントアウトするか行を削除する
  ], 
  // (中略)
}

表示例:

後注と脚注(1)

後注と脚注(2)

脚注(テーマ限定:theme-techbookのみ)

もしテーマとして @vivliostyle/theme-techbook を選んでいれば、脚注(ページ直下に出すタイプの注)を利用できます。

記法:

こちらは脚注<span class="footnote">ページ直下に表示される</span>です。

具体例は後注のものを参照してください。

縦中横(テーマ限定:theme-bunkoのみ)

もしテーマとして @vivliostyle/theme-bunko を選択していれば、縦中横の記法が使えます。

縦中横とは、縦組みの文書の中で横組みすることです。「42」のような半角英数字は、そのまま縦書きの文章に埋め込むと90度回転した状態で組まれてしまいます。そこで縦中横を指定すると、本文が縦書きの中でも横書きの状態(読者にとって自然に読める方向)で「42」が表示されます。

縦中横は <span class="tcy">42</span> のように指定します。

VFMでの記述:

 アレクサンドル・グロタンディークはこう言った。

「たとえば57は素数だが……」

 生命、宇宙、そして万物についての究極の疑問の答え、それは<span class="tcy">42</span>だった。

表示:

縦中横の例

縦書きのための補足:段落の扱いについて

先ほどの例では、次のルールで段落をつくりました。

  • 各段落は全角スペースではじめる(ただし行頭の括弧は例外)
  • 各段落間は空行を空ける(Enterキー2回)

このようにすれば、Vivliostyle上で小説の組み方に近いレイアウトが実現できると思われます。ただし一般的なテキスト形式の小説原稿のように「各段落間で空行を空けない」形式の場合はレイアウトが崩れます。たとえばテキストエディタ等で使える正規表現を使えば、次のように置換するとよいでしょう。

  • 検索:\n([□「])
    • ただしは全角スペース
  • 置換:\n\n$1
    • $1は「検索」で丸括弧と角括弧に囲まれていた文字(=全角スペースと)を表す
    • テキストエディタによっては、$1ではなく\1の場合もある

注意:数式は(そのままでは)使えない

VFMの仕様(pre-release)にはMath equationがあります。おそらくKaTeXによって数式を出力できる仕様となっているようです。

しかし現状では期待通りに出力されません。

KaTeX のスタイルシートとフォントがロードされていないため数式の表示にはなりません。

VFM→HTML変換にKaTeXによるHTMLへの変換を組み込むのであれば、https://github.com/KaTeX/KaTeX#starter-template にあるように HTML に次のようなスタイルシート指定が必要です。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css" integrity="sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X" crossorigin="anonymous">

Math equation で数式が正しく表示されない · Issue #36 · vivliostyle/vfm

なおVivliostyle.js自体は、HTMLのレンダリングができれば数式の出力は可能です。たとえばサンプル | Vivliostyleの一覧にある「宇宙論入門(論文)」では、MathJaxによる数式レンダリングが行われています[3]

VFMの技術的詳細

少し技術的詳細に立ち入ります。VFMの実装はvivliostyle/vfmにあります。この中のretrive-parse.tsに、実際のVFMの定義が書いてあります。

ソースコードから推測すると、VFMは「remark由来の記法」と「VFM独自の記法」に大きく分類できます。そしていわゆるGFMは、実際には「remarkで定義されたGFM」のようです。

revive-parse.ts
import breaks from 'remark-breaks';
import footnotes from 'remark-footnotes';
import frontmatter from 'remark-frontmatter';
import math from 'remark-math';
import markdown from 'remark-parse';
import slug from 'remark-slug';
import unified from 'unified';
import { mdast as attr } from './plugins/attr';
import { mdast as code } from './plugins/code';
import { mdast as fencedBlock } from './plugins/fenced-block';
import { mdast as metadata } from './plugins/metadata';
import { mdast as ruby } from './plugins/ruby';
import { mdast as section } from './plugins/section';
import { mdast as toc } from './plugins/toc';
import { inspect } from './utils/debug';

export default [
  [markdown, { gfm: true, commonmark: true }],
  fencedBlock,
  ruby,
  breaks,
  [footnotes, { inlineNotes: true }],
  math,
  attr,
  slug,
  section,
  code,
  toc,
  frontmatter,
  metadata,
  inspect('mdast'),
] as unified.PluggableList<unified.Settings>;

おわりに

GitHub Flavored Markdown(GFM)を拡張したMarkdown方言として、Vivliostyle Flavored Markdown(VFM)を紹介しました。

VFMはまだまだpre-release/working draftのため、今後も仕様が変わっていくと思われます。まだ不完全な記法が今後実装される一方で、現状のVFMを見る限り「微妙に足りない」部分もまだまだあります。

一方でMarkdownは「微妙に足りない」からこそ記法が覚えやすい側面もあります。記法が足りなければHTMLを直書きすればよいのです。Vivliostyle.jsは最終的にHTML/CSSを読み込むので、VFMを越えるようなカスタマイズもHTML/CSSで行える拡張性があります。筆者としては、現状のVFMは「ちょうどいい記法」のように思います。

次回はいよいよ、「技術同人誌をつくる」フェーズに入ります。小さい本のサンプルを作り、印刷所に(おそらく)入稿可能なPDFを生成するところまでいく予定です。

脚注
  1. https://docs.vivliostyle.org/#/ja/create-book#gfm-github-flavored-markdown ↩︎

  2. VFMの仕様では、標準的な記法ではないようです。vivliostyle/vfm: revive-parse.tsremark-footnotesが記述されています。なおVFMの仕様は2020-12-12時点でpre-releaseかつworking draftのため、仕様が今後変わっていく可能性が高いです。 ↩︎

  3. https://github.com/jagat-xpub/cosmology/blob/gh-pages/markup-notes.md ↩︎