约 1324 字
预计阅读 3 分钟
在Hugo博客中正确渲染多行数学公式
2024-02-20
博客
AI 摘要
109酱

2024.10.2 更新:

由于 BootCDN 受到污染,请自行寻找替代 CDN,如 jsDelivr 及其镜像等。

第二天更新:

今天发了篇数学笔记,然后被 KaTeX 挤到一起的公式和文字气到脑溢血……

已经改用 MathJax 了,把下面的代码改成这个就行。顺带赠送物理和化学公式渲染。

{{/* MathJax */}}
<link rel="preload" href="https://cdn.bootcdn.net/ajax/libs/mathjax/3.2.2/es5/tex-chtml.js" as="script">
<script async src="https://cdn.bootcdn.net/ajax/libs/mathjax/3.2.2/es5/tex-chtml.js"></script>
<script>
  window.MathJax = {
    tex: {
      inlineMath: [['$', '$'], ['\$', '\$']],
    },
    loader: {
      load: ['output/chtml']
    }
  };
</script>

更新:由于 bootcdn 的安全性问题,请更换其他可用 CDN。


各位老友们好,我是 Chlorine。本期可以说是建站教程的一个小番外,也是我迄今为止用时最短的一次折腾。

作为计算机系的学生,我对于在博客中插入数学公式还是有一定需求的,不仅是技术博客的刚需,有时候对于整活也是必要的。比如:

$$ \begin{cases} x = \sin t, \\ y = \frac{t \cos t}{2} \end{cases} \quad 0 \leq t \leq 2 \pi $$

至于这个参数方程是什么含义,大家可以找个绘图软件,比如 Desmos 或者 Geogebra 试一下(doge)。

但是,就在我昨天发布第一条数学笔记的时候,我发现我的 KaTeX 迟迟无法正确渲染一些公式,例如 \left\{。刚开始我没太在意,随便试了几种方法,改正了就完事了。

但是今天,在我打出上面那串参数方程的时候,我突然发现,换行符 \\ 没生效。

黑人问号.webp
黑人问号.webp

我不信邪,刚刚试了一下这个矩阵式的公式块:

$$ \mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix} \mathbf{i}& \mathbf{j}& \mathbf{k} \\[0.4em] \frac{\partial X}{\partial u}& \frac{\partial Y}{\partial u}& 0 \\[0.4em] \frac{\partial X}{\partial v}& \frac{\partial Y}{\partial v}& 0 \\[0.4em] \end{vmatrix} $$

发现也没正确渲染。

这可麻烦了,毕竟这学期的 VA(2)和高代(高等线性代数选讲),上学期还没填的线代可都靠着多行公式环境活呢。

问了 GitHub Copilot 和 Kimi AI,都没得到什么有用的信息,遂一头问号大如斗,问号随风满地走。

再回去看那串没被渲染的公式,突然发现了奇怪的东西:

这换行符咋就剩下一个反斜杠了?

众所周知,反斜杠在 Markdown 中是转义符,双反斜杠在单纯的 Markdown 环境里会被解读成单反斜杠。会不会 KaTeX 和 Hugo 内置的 goldmark 渲染器冲突了?毕竟,我的 KaTeX 是自己加的,与原本的工程冲突也很正常。

于是前往收集信息,最终找到了解决方案。

如果你已经引入了 KaTeX,请跳过这一部分。

众所周知,Markdown 中输入数学公式靠的是 LaTeX,而 KaTeX 是一个轻量化的 LaTeX 公式渲染器。KaTeX 的本质就是一堆 js 和 CSS 文件,因此用 CDN 引入就好了。

themes/<你的主题>/layouts/partials/head.html 中加入这段代码即可:

{{/* KaTeX */}}
<link rel="preload" href="https://cdn.bootcdn.net/ajax/libs/KaTeX/0.16.8/katex.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript>
  <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/KaTeX/0.16.8/katex.min.css">
</noscript>
<script defer src="https://cdn.bootcdn.net/ajax/libs/KaTeX/0.16.8/katex.min.js" crossorigin="anonymous"></script>
<script defer src="https://cdn.bootcdn.net/ajax/libs/KaTeX/0.16.8/contrib/auto-render.min.js" crossorigin="anonymous"
    onload="renderMathInElement(document.body, {
          delimiters: [
            { left: '$$', right: '$$', display: true },
            { left: '$', right: '$', display: false },
            { left: '\$', right: '\$', display: false }
          ]
        });"></script>

goldmark 有一个叫 passthrough 的插件,可以识别数学公式的定界符,使得多行公式的双斜杠免遭毒手。

config.toml 文件的 markup 下添加这段代码:

[markup.goldmark.extensions.passthrough]
      enable = true
      delimiters.block = [
        ["\\[", "\\]"],
        ["$$", "$$"]
      ]
      delimiters.inline = [
        ["\\(", "\\)"],
        ["$", "$"]
      ]

如果你使用的是 config.yaml,那么就添加:

markup:
  goldmark:
    extensions:
      passthrough:
        delimiters:
          block:
          - - \[
            - \]
          - - $$
            - $$
          inline:
          - - \(
            - \)
          - - $
            - $
        enable: true

如果是 config.json 就使用这个:

然后就可以正确进行渲染了~

  1. Hugo 官方推荐的方案与这里有所不同,如果你希望能使用 front matter 来控制渲染与否,可以参考这里
  2. 如果你有渲染物理/化学公式的需求,MathJax 会更好。KaTeX 需要再引入一些扩展包,我没那个需求,就不整了。

下面是一个物理公式的示例:

$$ d \mathord{ \buildrel{ \lower3pt \hbox{$ \scriptscriptstyle \rightharpoonup$}} \over B} = \frac{{{ \mu _0}}}{{4 \pi }} \frac{{Idl \times \mathord{ \buildrel{ \lower3pt \hbox{$ \scriptscriptstyle \rightharpoonup$}} \over r} }}{{{r^3}}} = \frac{{{ \mu _0}}}{{4 \pi }} \frac{{Idl \sin \theta }}{{{r^2}}} $$

下面是一个化学公式的示例:

$$ \ce{Zn^2+ <=>[+ 2OH-][+ 2H+] $\underset{\text{amphoteres Hydroxid}}{\ce{Zn(OH)2 v}}$ <=>[+ 2OH-][+ 2H+] $\underset{\text{Hydroxozikat}}{\ce{[Zn(OH)4]^2-}}$} $$

其真实效果应该是:

使用Obsidian进行的渲染
使用Obsidian进行的渲染

  1. 参考资料:Hugo 数学公式支持 | Finley's Blog (f1nley.xyz)
在Hugo博客中正确渲染多行数学公式
https://www.yoghurtlee.com/hugo-math-rendering/
作者
Chlorine
发布于
2024-02-20