えびちゃんの日記

えびちゃん(競プロ)の日記です。

はてなブログで KaTeX を使う

まとめておいた方がいいかなと思ったので。

導入方法

$\KaTeX$ の JavaScript を読み込む必要があります。各記事のヘッダ部分にそれを追加します。

以下のスクショを参考に、管理画面 (デザイン) > カスタマイズ > ヘッダ > ブログタイトル下の入力欄を探します。

デザイン

デザイン > カスタマイズ > ヘッダ

追記:管理画面 (設定) > 詳細設定 > 要素にメタデータを追加 の部分に書く方がいいかもしれません?

そこに、$\KaTeX$ > Browser > Starter template<head>...</head> の中の内容を入れます。 実際には、使い勝手の向上のために多少手を加えたいので、まるっとコピペできる用のものは記事下部に載せます。

はてな記法tex 記法との比較

help.hatenablog.com

たとえば、以下のように書きます。

[tex: \sum_{i=1}^n \left\lfloor\frac{n}{i}\right\rfloor = O(n\log(n))]

あるいは、_ \ などをエスケープして以下のように書く癖をつけた方が無難かもしれないので、以下のようにも書きます。

[tex: \\sum\_{i=1}^n \\left\\lfloor\\frac{n}{i}\\right\\rfloor = O(n\\log(n))]

どちらの場合も、次のように表示されます。

 \sum_{i=1}^n \left\lfloor\frac{n}{i}\right\rfloor = O(n\log(n))

$\KaTeX$ を導入した場合は次のように書きます。

\\(\\sum\_{i=1}^n \\left\\lfloor\\frac{n}{i}\\right\\rfloor = O(n\\log(n))\\)

あるいは \\(...\\) ではなく $...$ を用いることもできます。

$\\sum\_{i=1}^n \\left\\lfloor\\frac{n}{i}\\right\\rfloor = O(n\\log(n))$

どちらの場合も、次にように表示されます。

$\sum_{i=1}^n \left\lfloor\frac{n}{i}\right\rfloor = O(n\log(n))$

フォントが違っているため、(フォント関連の設定をしている場合を除き)どちらの記法で書かれた記事かは見ればわかりがちです。

キーワードリンクに関して

はてな」のように、特定のキーワードにリンクがつく機能です。

markdown の処理やキーワードリンクの処理がなされた後、$\KaTeX$ による数式処理がされるわけですが、数式中にリンクが含まれているとうまく変換してくれません。 解決はできるので大丈夫ですが、素朴にやると変になる例を先に挙げておきます。

衝突する例と ad hoc な回避策

たとえば、$m-1$ のように書きたい場合でも $m-1$ のようになってしまいます。このケースでは $m-1$ の代わりに $m -1$ のように書くことで回避できますが、うれしくありません。

また、$∧$ (\wedge) を書きたい場合、$\wedge$ のようになってしまいます。 $\KaTeX$ は記号の直接入力ができるので、$∧$ と入力すれば $∧$ を出せますが、入力が多少大変です。

さらに、$\arcsin$ (\arcsin) を書きたい場合も、$\arcsin$ のようになってしまいます。 これは、(数式中の空白が無視されることを利用して)$\\gdef\\asin{\\operatorname{arcsi n}}$ のようなマクロを作ってから $\\asin$ のように書けば回避できますが、かなりうれしくないです。

解決方法 1

さて、はてな有料版であればキーワードリンク無効化のオプションがあるらしいですが、これだけのために有料版を使うのもうれしくなさそうです。 上記のはてな記法ヘルプを見ると、「自動リンク停止記法」というのがあります。

はてな はてな []はてな[] はてな []はてな[]

はてな はてな はてな はてな はてな

これを数式に対して使う方法があります。[]...[]<span> で囲まれてしまい、$ の中に <span> があるとうまくいかないようなので*1、特定箇所だけではなく、数式全体を囲む必要があります。

$\\[]arcsin[]$ []$\\arcsin$[] 

$\arcsin$ $\arcsin$

複数行についても回避可能なようです。

[] $$
\\begin{aligned}
x &= y \\\\
&= m-1
\\end{aligned}
$$ []

$$ \begin{aligned} x &= y \\ &= m-1 \end{aligned} $$

汎用的な方法ではありますが、数式を $...$ ではなく []$...$[] で囲むのはちょっと面倒そうです。

あれ、もしかして記事全体を [] で囲む(記事の先頭と末尾に [] を書く)と解決しますでしょうか。

解決方法 2

テンプレートに onload="renderMathInElement(document.body); と書いてある通り、ロードされた後の所望のタイミングで数式の組版ができることがわかります。 よって、「数式と衝突しそうな単語のキーワードリンクを除去してから組版する」という方法があります。

(別に数式関係なく無効化したいという人はそれでもいい気もするのですが)さすがにアレかなと思い、自分で列挙しています。 キーワードリンクに追加される単語は随時追加されているようなので、昔の記事が勝手に変な感じになる可能性はありそうです。 これはかなり嫌ですが、共通設定のヘッダ(上記で言及した「ブログタイトル下」の部分)に追記するだけで直せるのでいいかなという感じです。

具体的な記述に関しては以下のコピペ用部分を見てください。

マクロなど

人によっては、たとえば以下のようなマクロを頻繁に使うかもしれません。

  • $\gcd(x, y)$ (\\gcd(x, y))
  • $\polylog{n}$ (\\polylog(n))
  • $\floor{n/i}$ (\\floor{n/i})
  • $\angled{O(n), O(1)}$ (\\angled{O(n), O(1)})

こうしたものを各記事で定義することもできるのですが、毎回書くのは嫌そうです。 これも、共通のヘッダに書くことができます。 具体的な記述は以下を参考にしてください。

note: 記事中での定義は以下のようにして可能です。

$$
\\gdef\\foo{\\operatorname{foo}}
\\gdef\\bar#1#2{\\operatorname*{bar}\_{#1}\^{#2}}
$$

$$\\foo \\bar{a}{b}$$

$$ \gdef\foo{\operatorname{foo}} \gdef\bar#1#2{\operatorname*{bar}_{#1}^{#2}} $$

$$\foo \bar{a}{b}$$

コピペ用

<script>
    'use strict';
    const mathWord = new Set([
        // 必要に応じて追加する
        'arccos',
        'arcsin',
        'arctan',
        'k-1',
        'l-1',
        'm-1',
        'qed',
        'sigma',
        'tau',
        'wedge',
    ]);
    const isMathWord = w => mathWord.has(w.toLowerCase());
    function cancel(el) {
        Array.from(el.querySelectorAll('a.keyword'))
            .filter(e => isMathWord(e.innerHTML))
            .forEach(e => e.outerHTML = e.innerHTML);
    }
    const KaTeXOptions = {
        delimiters: [
            {left: '$$', right: '$$', display: true},
            {left: '\\[', right: '\\]', display: true},
            {left: '$', right: '$', display: false},
            {left: '\\(', right: '\\)', display: false},
        ],
        macros: {
            '\\halfopen': '[#1, #2)',
            '\\floor': '\\lfloor #1\\rfloor',
            '\\ceil': '\\lceil #1\\rceil',
            '\\Floor': '\\left\\lfloor #1\\right\\rfloor',
            '\\Ceil': '\\left\\lceil #1\\right\\rceil',
            '\\angled': '\\langle #1\\rangle',
            '\\Angled': '\\left\\langle #1\\right\\rangle',
            '\\lcm': '\\operatorname*{lcm}',
            '\\gcd': '\\operatorname*{gcd}',
            '\\poly': '\\operatorname{poly}',
            '\\polylog': '\\operatorname{polylog}',
        }
    };
</script>

<!-- See https://katex.org/docs/browser.html -->

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css" integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">

<!-- The loading of KaTeX is deferred to speed up page rendering -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js" integrity="sha384-PwRUT/YqbnEjkZO0zZxNqcxACrXe+j766U2amXcgMg5457rve2Y7I6ZJSm2A0mS4" crossorigin="anonymous"></script>

<!-- To automatically render math in text elements, include the auto-render extension: -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"
    onload="cancel(document.body);renderMathInElement(document.body, KaTeXOptions)"></script>

参考

markdown の記法と衝突しないようにするための書き方など

kmyk.github.io

はてな記法からの移行に関してなど

noimin.hatenablog.com

過去の記事で $...$ などを書いていなければ、$\KaTeX$ を導入しても過去の記事への影響は基本的にはないのではなさそうな気もします。

おきもち

人々が「はてなで数式を書くのしんどい」と言っているとき、はてな記法tex 記法に対して言っているのか、そもそも TeX 自体がしんどいのか、$\KaTeX$ を使っているけれども markdown と衝突するため \_\\ などと書いたり、はてな記法との衝突を避けるために \^ のようにしたりするのが嫌なのか、などが場合によりそうなので、見極める必要がありそうです。

[tex: ...] と書くのが面倒というだけであれば、$\KaTeX$ を導入するのが一番楽なのではないでしょうか。

おわり

😀  \\sum\_{i=1}^n \\left\\lfloor\\frac{n}{i}\\right\\rfloor = O(n\\log(n))
😄 $\\sum\_{i=1}^n \\left\\lfloor\\frac{n}{i}\\right\\rfloor = O(n\\log(n))$
😣 $\\arcsin$
😄 $\\arcsin$

楽に書けるようになるとよいですね。

*1:タグのネスト関連の事情。