HUGOで数式を表示する
概要
HUGOで数式を表示できるようにKaTexを設定します。
A Tour of Goの記事を書いた際に数式を挿入したくなり設定方法を調べました。
以下でKaTexを参照する設定を行なっていきます。
HUGOのテーマにはAnankeを使用していますので、Anankeに合わせた設定です。
違うテーマを使用されている場合は適宜読み替えてください。
環境
- Macbook Pro 13inch, 2016
- macOS Catalina version 10.15.6
- Brave Browser v 1.14.81
- Hugo v0.75.1
- Anakne v2.6.5
- KaTex 0.12.0
KaTex用のhtmlを追加
KaTexを参照するためのhtmlを/layouts/partials/
以下に追加します。
僕はそのままkatex.html
としました。
DocumentationのAuto-render Extensionで説明されている通り、以下のようにタグを実装します。
<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">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.js" integrity="sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/contrib/auto-render.min.js" integrity="sha384-mll67QQFJfxn0IYznZYonOWZ644AWYC+Pt2cHqMaRhXVrursRwvLnLaebdGIlYNa" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
// ...options...
});
});
</script>
オプションのカスタマイズ
delimiters
数式を検索するための区切り文字をカスタマイズできます。
既定値では以下の通りです。
[
{left: "$$", right: "$$", display: true},
{left: "\\(", right: "\\)", display: false},
{left: "\\[", right: "\\]", display: true}
]
$ ... $
を使用してインライン演算のサポートを追加するように変更しました。
スクリプトタグ内のoptionsに下記を追加します。
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
// ...options...
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
]});
});
<script>
ルールは順番に処理されるため、$
ルールを最初に配置すると、$$
が空の数式としてキャッチされます。
$
ルールは必ず$$
ルールの後になるように定義してください。
strict
また、KaTexにはstrict
というオプションがあり、既定値では"warn"
になっています。
この設定だと改行を使ったときに、JavaScriptのコンソールで警告が表示されます。
表示したくない場合はstrict
を"ignore"
またはfalse
に設定します。
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
// ...options...
strict: false, // これを追加
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
]});
});
<script>
フロントマターにKaTex用の変数を追加
数式を表示しない記事でKaTexを参照しても意味がありません。
参照の有無を分岐できるように、フロントマターにKaTex用の変数を追加します。
フロントマターに定義した変数は.Params.<変数名>
で参照が可能になります。
---
title: "HUGOで数式を表示する"
...
katex: true # ←こんな感じ
...
---
/archetypes/default.md
に既定値を追加しておけば、true/false
の変更だけで済みますが、そんなに数式を使用する予定もないので、今回は入れないことにしました。
必要になったら都度設定します。
KaTex用のhtmlを参照する
katex.html
を参照に追加します。
Anankeでスクリプトをヘッダに追加する場合は/layouts/partials/head-additions.html
に追加するように公式では説明されているのですが、僕の環境ではうまく動作しません。
解決に時間が掛かりそうなので、とりあえず/layouts/_default/baseof.html
で直接参照することにしました。
+ {{ if .Params.katex }}
+ {{ partial "katex.html" . }}
+ {{ end }}
{{ if eq (getenv "HUGO_ENV") "production" | or (eq .Site.Params.env "production") }}
{{ template "_internal/google_analytics_async.html" . }}
{{ end }}
Google Analyticsの参照設定の上あたりに追加しています。
{{ if .Params.katex }}
で条件分岐を行い、katex = true
の場合にkatex.html
を読み込みます。
これは余談ですが、AnankeにはBodyのフッタ部でもスクリプトを参照する箇所(/layouts/partials/site-scripts.html
)があるのですが、こちらではフロントマターで定義した変数が参照できませんでした。
数式の表示
以上で準備は完了です。
あとはLaTex形式で数式を埋め込めばKaTexが自動で変換してくれます。
下記の表示例はA Tour of Goで出題された演習内容のものです。
インライン数式での表示例
シーザー暗号
$E_n(x) = (x + n) mod 26$
$E_n(x) = (x + n) mod 26$
ディスプレイ数式での表示例
フィボナッチ数列
$$
F_0 = 0, \newline
F_1 = 1, \newline
F_{n+2} = F_n + F_{n+1} (n \geq 0)
$$
$$ F_0 = 0, \newline F_1 = 1, \newline F_{n+2} = F_n + F_{n+1} (n \geq 0) $$
\newline
をつけると改行できます。
\\
はうまく動作しません。1
ディスプレイ数式でのセンター表示はLaTexのデフォ値みたいなので、左寄せにする場合はCSSをゴニョゴニョする必要がありそうです。
LaTexの構文での左寄せは試してみたのですが、うまく動作しませんでした。
左寄せはとりあえず保留します。2
まとめ
HUGOで数式を表示できるようにKaTexを設定しました。
見た目も綺麗だし表示も速いので概ね満足しています。
MathJaxがメジャーぽかったので初めはMathJaxを参照に追加してみたのですが、表示がワンテンポズレるので、他のものを探して最終的にKaTexを採用することにしました。
The fastest math typesetting library for the web.
と謳っているだけあってMathJaxと比べても表示はかなり速いです。
ガッツリ数式を使って何かしたい訳でもないので、速さを重視しました。
参照追加するだけだからすぐ終わるだろうと取り掛かったのですが、結局3時間くらい掛かりました。
以上です。