Web-Mathematik (MathJax / KaTeX)

TeX läuft nicht im Browser. Die Werkzeuge, die LaTeX-Mathematik auf eine Webseite bringen – MathJax und KaTeX –, sind daher beide Neuimplementierungen des TeX-Formelsatzes in JavaScript, und beide haben auf dasselbe Problem entgegengesetzt gewettet. Dieselben 500 Formeln zu setzen kostete hier KaTeX 45 Millisekunden und MathJax 264. Wer allein nach Tempo wählt, stolpert allerdings anderswo: Keines von beiden behandelt $...$ standardmäßig als Mathematik. Diese Seite behandelt den Unterschied im Entwurf, die Fehlermeldungen, die wirklich erscheinen, und die Frage, ob das in eine Seite eingefügte TeX danach noch vorhanden ist.

KaTeX oder MathJax: welches gehört auf die Seite

Viele Formeln und Tempo zählt: KaTeX. Das geschriebene LaTeX soll möglichst unverändert durchgehen: MathJax. Der Geschwindigkeitsunterschied ist keine Frage des fleißigeren Optimierens, sondern der Form der Schnittstelle. KaTeX’ katex.renderToString(...) liefert eine Zeichenkette synchron zurück – das HTML liegt im Moment des Aufrufs vor, es wird nichts nachträglich eingefügt und nichts springt um. MathJax dagegen ist im Browser um MathJax.typesetPromise() herum gebaut und gibt, wie der Name sagt, ein Promise zurück. Der kurze Blick auf ein rohes \frac{1}{2}, den Lesende gelegentlich erhaschen, ist eine Nebenwirkung dieser Asynchronität.

html
<!-- MathJax 3: configure BEFORE the script tag loads -->
<script>
  window.MathJax = {
    tex: { inlineMath: [["$", "$"], ["\\(", "\\)"]] }
  };
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

<!-- KaTeX: stylesheet, engine, then the auto-render pass -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex/dist/contrib/auto-render.min.js"
        onload="renderMathInElement(document.body);"></script>

Warum $...$ nicht gesetzt wird – der Kommentar in KaTeX’ eigenem Quelltext

Keine der beiden Bibliotheken behandelt $...$ von Haus aus als Inline-Mathematik. Das ist kein Versehen, sondern eine bewusste Voreinstellung. Im Quelltext von KaTeX’ auto-render steht der Eintrag für $ auskommentiert da, mit der Begründung eine Zeile darüber: „LaTeX uses $…$, but it ruins the display of normal $ in text“. Zwei Währungszeichen in einem Absatz, und alles dazwischen wird zur Formel. MathJax hält es genauso: inlineMath ist nur \(...\), displayMath sind $$...$$ und \[...\]. Ein guter Teil aller Meldungen „meine Formeln erscheinen als Quelltext“ hat genau hier seine Ursache.

js
// KaTeX auto-render, default delimiters (dist/contrib/auto-render.js):
//   { left: "$$",  right: "$$",  display: true  }
//   { left: "\\(",  right: "\\)",  display: false }
//   { left: "\\[",  right: "\\]",  display: true  }
//   plus \begin{equation} \begin{align} \begin{alignat} \begin{gather} \begin{CD}
//
// and this line is deliberately commented out in the source:
//   // LaTeX uses $...$, but it ruins the display of normal `$` in text:
//   // {left: "$", right: "$", display: false},

// turn it on yourself only if the page has no currency amounts:
renderMathInElement(document.body, {
  delimiters: [
    { left: "$$", right: "$$", display: true },
    { left: "$",  right: "$",  display: false },
    { left: "\\(", right: "\\)", display: false },
    { left: "\\[", right: "\\]", display: true }
  ],
  ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code"]
});

Was KaTeX nicht kann – und die Fehlermeldungen, die es ausgibt

KaTeX unterstützt eine Teilmenge der LaTeX-Mathematik; alles darüber hinaus wird als Ausnahme geworfen. Der Wortlaut ist einheitlich: KaTeX parse error: Undefined control sequence: \eqref at position 1: und so fort. Die schmerzlichste Lücke ist der Querverweis auf Formelnummern – weder \label noch \eqref sind definiert, sodass ein Dokument, das seine Formeln nummeriert und darauf zurückverweist, mit bloßem KaTeX nicht auskommt. Chemie geht ebenfalls nicht durch: \ce{H2O} verlangt die separate Erweiterung mhchem. Der andere Dauerbrenner lautet KaTeX parse error: {align} can be used only in display mode. und erscheint, wenn eine align-Umgebung zwischen Inline-Begrenzern steht.

Ein Missverständnis ist allerdings, KaTeX könne keine Makros. \newcommand, \def und \gdef funktionieren alle, und übergibt man der Option macros ein leeres Objekt, so überdauert eine mit \gdef gemachte Definition die einzelnen Aufrufe. Genau so schleust man eine seitenweite Makro-Präambel genau einmal ein. MathJax bringt umgekehrt rund dreißig Nachbauten von TeX-Paketen mit – darunter ams, amscd, mathtools, mhchem, cancel, braket, bussproofs, empheq, colortbl –, und diese Liste ist es, was „breitere Kompatibilität“ tatsächlich bedeutet. Und wer nicht will, dass eine einzige fehlerhafte Formel die Seite zerlegt, merke sich throwOnError: false: KaTeX wirft dann keine Ausnahme, sondern setzt den fehlerhaften Quelltext in Rot (#cc0000) und macht weiter.

Was geschrieben wurdeKaTeXMathJax
\frac \int \underbrace \textgehtgeht
\newcommand \def \gdeffunktioniert (bleibt über macros erhalten)funktioniert (über die macros-Konfiguration)
\label \eqrefneinUndefined control sequencefunktioniert (Nummerierung über tags)
\ce{H2O}braucht die separate Erweiterung mhchemmitgeliefert
align (inline){align} can be used only in display mode.geht

Ist MathML inzwischen brauchbar? Die Lücke schloss sich 2023

Alle großen Browser können MathML darstellen. Am längsten leer blieb der Platz bei Chrome: Die Unterstützung kam, verschwand wieder und kehrte in Version 109 endgültig zurück (Edge ab derselben 109). Firefox hat sie seit Version 2, Safari seit 10. Gleichwohl gibt es noch wenig Anlass, MathML von Hand zu schreiben. Wichtiger ist, dass beide Bibliotheken MathML in ihre Ausgabe legen. KaTeX setzt neben das sichtbare HTML stets ein <math>-Element, und MathJax’ Standardbündel tex-mml-chtml.js lädt von vornherein die Erweiterung, die MathML für Hilfstechnik ergänzt. Dieser verborgenen Schicht ist es zu verdanken, dass ein Screenreader die Formel überhaupt vorlesen kann.

Überlebt das TeX? Aus welchem sich Formeln zurückkopieren lassen

Mit KaTeX überlebt es, mit MathJax standardmäßig nicht. Jeder MathML-Baum, den KaTeX ausgibt, enthält ein <annotation encoding="application/x-tex">, und darin steht das ursprüngliche TeX. Gibt man x^2+1 hinein, liegt die Zeichenkette x^2+1 weiterhin irgendwo in der Ausgabe. Zusätzlich liefert die Distribution eine Erweiterung copy-tex mit, deren eigener Quellkommentar lautet: „Replace .katex elements with their TeX source“ – geladen, legt sie beim Kopieren einer markierten Formel $x^2+1$ in die Zwischenablage statt einer Reihe von Glyphen. MathJax’ gewöhnliche HTML-Ausgabe trägt das ursprüngliche TeX nicht. Seine Antwort ist stattdessen das Kontextmenü: „Show Math As“, worüber sich die Originalform zurückholen lässt.

html
<!-- what KaTeX puts in the DOM for x^2+1 -->
<span class="katex"><span class="katex-mathml"><math
    xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow>
  <msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>1</mn>
  </mrow><annotation encoding="application/x-tex">x^2+1</annotation>
</semantics></math></span><span class="katex-html" aria-hidden="true">...</span></span>

<!-- load this and Ctrl-C on a formula yields $x^2+1$, not glyphs -->
<script defer src="https://cdn.jsdelivr.net/npm/katex/dist/contrib/copy-tex.min.js"></script>

Eigene Makros bis in den Browser bringen

Hier verläuft die Grenze zu den Werkzeugen, die ein ganzes Dokument nach HTML wandeln. MathJax und KaTeX erhalten beide nur Bruchstücke von Mathematik; die Präambel liest keines von beiden. Ein \newcommand{\R}{\mathbb{R}} am Anfang der .tex erreicht den Browser also nie, und \R erscheint undefiniert und rot. Makros müssen gesondert über das Konfigurationsobjekt übergeben werden. Dieselbe Falle lauert auf der Konverterseite: Der Modus mathjax von make4ht belässt die Mathematik als LaTeX im HTML, sodass eigene Makros auch dort nicht expandiert werden. Die Konverterseite ist Sache von „LaTeX → HTML“, doch das Gegenmittel ist beidseits dasselbe – die Makrodefinitionen in einer Datei sammeln und sowohl TeX als auch JavaScript daraus lesen lassen.

js
// KaTeX: one shared object, and \gdef survives from call to call
const macros = {};
katex.renderToString("\\gdef\\R{\\mathbb{R}}", { macros });
katex.renderToString("f\\colon \\R \\to \\R", { macros });   // \R resolves

// or declare them up front, the same way for the auto-render pass:
renderMathInElement(document.body, {
  macros: { "\\R": "\\mathbb{R}", "\\eps": "\\varepsilon" },
  throwOnError: false          // print the bad source in red, do not break the page
});

// MathJax 3: the equivalent lives in the config object
window.MathJax = {
  tex: {
    macros: { R: "\\mathbb{R}", eps: "\\varepsilon" },
    tags: "ams"                // this is what enables \label and \eqref
  }
};
  • Formeln erscheinen als Quelltext → die Begrenzer verdächtigen. $...$ ist bei KaTeX wie bei MathJax voreingestellt aus.
  • Das Dokument verwendet \eqref → MathJax wählen und tags: "ams" setzen. KaTeX hat überhaupt keine Nummerierung.
  • Eine Übersichtsseite mit Hunderten Formeln → KaTeX. Synchrones Rendern heißt: Das Layout springt hinterher nicht.
  • Es gibt eigene Makros → in macros übergeben. Die Präambel erreicht den Browser nie.
  • Eine kaputte Formel darf die Seite nicht mitreißen → in KaTeX throwOnError: false: rot ausgeben und weitermachen.
  • Das ganze Dokument soll ins Web → das ist nicht Aufgabe eines Formel-Renderers (siehe „LaTeX → HTML“).