はじめに
技術ブログや学習サイトで数式を表示したいとき、多くの人がまず候補に挙げるのがMathJaxです。しかし実際に導入してみると、ページ全体の再描画(リフロー)が発生してガタつく、数式が多いページでは表示が遅い、といった悩みに直面した経験はないでしょうか。
そんな課題を解決してくれるのがKaTeXです。KhanAcademyが開発したこのライブラリは、数式を同期的にレンダリングし、ページのリフローを必要としません。今回はKaTeXの特徴から実践的な使い方まで、順を追って紹介します。
とはいえ、読むより触った方が早いと思います。LaTeX記法を書き換えると数式がその場で更新されるサンプルを用意したので、先に挙動を見たい方はこちらからどうぞ。
KaTeXとは
KaTeXは、Webブラウザ上で数式を高速かつ高品質に表示するためのJavaScriptライブラリです。レイアウトエンジンはドナルド・クヌース氏が開発したTeXの組版アルゴリズムをベースにしており、数式組版における「金標準」の品質をブラウザ上で再現します。
主な特徴
- 高速性 - 数式を同期的にレンダリングするため、ページの再フローが発生しません。数式を多数含むページでも高速に表示できます。
- 依存関係なし - 外部ライブラリへの依存がなく、自己完結型なのでバンドルサイズを抑えたまま導入できます。
- サーバーサイドレンダリング対応 - Node.js上で事前に数式をHTML/CSSに変換できるため、静的サイトやSSRとも相性が良いです。
- 豊富なLaTeX互換性 - LaTeXおよび主要なLaTeXパッケージの多くの構文をサポートしています。
インストール
npmまたはyarnでインストールできます。
npm install katex
# または
yarn add katex
CDN経由で手早く試すことも可能です。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.18.1/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.18.1/dist/katex.min.js"></script>
KaTeXのサンプルを動かす
下のサンプルは、テキストエリアに入力したLaTeX記法をKaTeXのkatex.renderでリアルタイムに数式へ変換するものです。inputイベントのたびに再描画しているので、文字を打つと同時に結果が更新されます。試しに\frac{a}{b}のaやbをx^2のような別の式に置き換えてみたり、\sqrt{}や\sum_{i=1}^{n}を追記してみたりしてください。
要点だけを抜き出すと、KaTeXでのレンダリング部分はこれだけのコードです。throwOnError: falseを指定しておくと、不完全な数式を入力してもエラーで処理が止まらず、KaTeX自身がエラー内容を赤字で表示してくれます。
import katex from 'katex'
const el = document.getElementById('formula')
function render(tex) {
katex.render(tex, el, {
throwOnError: false,
displayMode: true,
})
}
input.addEventListener('input', () => render(input.value))
render(input.value) // 初期表示
実際に動かせるものが下です。KaTeXのCSSは<link>タグで読み込み、katex.renderの第2引数に渡したDOM要素へ数式を描画しています。
書き換えた瞬間に数式が更新されるので、LaTeXの記法とレンダリング結果の対応関係を体感しやすいはずです。たとえば\sqrt{a^2 + b^2}の\sqrtを\sum_{i=1}^{n} iに変えると総和記号に切り替わりますし、閉じカッコを消して\frac{a}{bのように壊すと、KaTeXがエラー箇所を赤字で示しつつ、それ以外の描画は継続してくれます。これが冒頭で触れた「同期的なレンダリング」の速さです。
基本的な使い方
最もシンプルな使い方は、katex.renderでDOM要素に直接数式を描画する方法です。
<div id="formula"></div>
<script>
katex.render(
"c = \\pm\\sqrt{a^2 + b^2}",
document.getElementById("formula"),
{ throwOnError: false }
);
</script>
Node.js環境では、HTML文字列として数式を生成できます。サーバーサイドで事前にレンダリングしたい場合に便利です。
import katex from "katex";
const html = katex.renderToString("E = mc^2", {
throwOnError: false,
});
console.log(html);
// => <span class="katex">...</span>
実践的なユースケース
KaTeXでインライン数式とブロック数式を切り替える
KaTeXには、文中に埋め込む「インライン数式」と、独立した行として中央揃えで表示する「ブロック数式」の2つの表示形式があります。どちらを使うかはkatex.renderのdisplayModeオプションで切り替えます。displayMode: false(既定値)だとインライン表示、displayMode: trueだとブロック表示になり、フォントサイズや行間の扱いが変わります。
import katex from 'katex'
// インライン数式(文章の中に埋め込む)
katex.render('E = mc^2', inlineEl, {
displayMode: false,
throwOnError: false,
})
// ブロック数式(独立した行として中央揃え)
katex.render('E = mc^2', blockEl, {
displayMode: true,
throwOnError: false,
})
下のサンプルでは、同じLaTeX数式をインラインとブロックの両方で同時にレンダリングし、見た目の違いを比較できるようにしています。テキストエリアの中身を書き換えると、両方の表示が同時に更新されます。
displayMode: falseのインライン数式は周囲のテキストと同じ行に収まるようフォントサイズが抑えられているのに対し、displayMode: trueのブロック数式は一段大きく、中央揃えで表示されるのが分かるはずです。段落中で軽く数式に触れたいときはインライン、証明や導出過程をじっくり見せたいときはブロックというように、displayModeを使い分けると読みやすさが大きく変わります。
KaTeXのエラー処理(無効なLaTeXの扱い)
ユーザー入力やCMSの本文など、外部から渡されたLaTeX記法をそのままKaTeXに渡す場面では、構文エラーへの対処が欠かせません。KaTeXは既定では無効な数式を渡すと例外を投げますが、throwOnError: falseにするとエラーを投げる代わりにerrorColorで指定した色(既定は赤)でエラー箇所を表示し、処理を継続してくれます。
import katex from 'katex'
try {
katex.render(tex, el, {
throwOnError: false, // 例外を投げず赤字で表示する
errorColor: '#cc0000',
});
} catch (e) {
// throwOnError: true の場合はここで ParseError を捕捉できる
console.error(e.message);
}
次のサンプルでは、throwOnErrorをチェックボックスで切り替えられるようにしました。オンのままカッコが閉じていない数式(例: \frac{a}{b)を入力するとKaTeXが赤字でエラー箇所を示しますが、チェックを外してthrowOnError: trueにすると同じ入力でkatex.renderが例外を投げ、try/catchでメッセージを捕捉する挙動を確認できます。
CMSや掲示板のようにユーザーが自由にLaTeXを書き込める環境では、1つの構文エラーでページ全体のレンダリングが止まらないようthrowOnError: falseを基本にしつつ、開発中のデバッグではthrowOnError: trueにしてtry/catchでエラー内容を詳しく確認する、という使い分けが実用的です。
Markdownブログに数式を組み込む
このブログのようにMarkdownベースのコンテンツで数式を扱いたい場合、remark-mathとrehype-katexを組み合わせることで、$...$や$$...$$の記法をそのままKaTeXでレンダリングできます。
npm install remark-math rehype-katex katex
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkMath from "remark-math";
import remarkRehype from "remark-rehype";
import rehypeKatex from "rehype-katex";
import rehypeStringify from "rehype-stringify";
const processor = unified()
.use(remarkParse)
.use(remarkMath)
.use(remarkRehype)
.use(rehypeKatex)
.use(rehypeStringify);
const file = await processor.process(
"二次方程式の解は $x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$ です。"
);
console.log(String(file));
これにより、記事中に埋め込んだLaTeX記法の数式が、ビルド時に静的なHTMLへ変換されます。クライアント側でのJavaScript実行が不要になるため、表示速度と初期描画のちらつき対策の両方に効果的です。
ページ内の複数数式を一括レンダリング
auto-render拡張機能を使うと、ページ内のテキストを自動的にスキャンし、区切り文字で囲まれた数式をまとめてレンダリングできます。
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.18.1/dist/contrib/auto-render.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
],
throwOnError: false,
});
});
</script>
ブログ記事や技術ドキュメントのように、数式がテキストに混在するページで特に力を発揮します。
まとめ
KaTeXは、TeXレベルの組版品質を保ちながら、同期的なレンダリングによって高速に数式を表示できるライブラリです。依存関係がなく軽量なため、既存のプロジェクトにも導入しやすいのが魅力です。
remark-mathやrehype-katexと組み合わせれば、Markdownベースのブログやドキュメントサイトにも自然に数式表現を取り込めます。数式表示の重さに悩んでいる方は、ぜひ一度KaTeXを試してみてください。