本文将介绍如何让 Typecho 支持对 LaTeX 格式的按需渲染。

首先可以打开这个网页查看最终效果。

为什么需要 LaTeX

LaTeX 是一种很厉害的排版系统,类似于 Microsoft Word。由于其对数学公式的支持十分强大,因此有时也只用它来输入数学公式。我们接下来仅探讨如何在 Typecho(Markdown) 中使用 LaTeX 输入数学公式并正确渲染不探讨如何使用 LaTeX 排版。LaTeX 作为一门独立的排版系统,不仅仅只是用来输入数学公式!

如何在前端渲染 LaTeX

我们可以使用 KaTeXMathJax 这两个 LaTeX 渲染库来实现,这篇文章将以 KaTeX 为例。

注意: LaTeX 是一种排版系统。KaTeXMathJax 是两个用于渲染 LaTeX 库的名字。

为什么不使用插件

插件固然方便,而且网上有关 Typecho 支持 LaTeX 的插件也很多。但是它们大多有一个相同的问题,不能按需渲染

大多数 Typecho 的插件都是基于 KaTeX 或 MathJax 的前端渲染方案,本质上就是在header中增加相关 JavaScript 代码和 CSS 样式表,从而让浏览器在加载时渲染 LaTeX 源码。但是,即使是号称最精简 LaTeX 渲染库——KaTeX,依旧是一个相当大的库。

如果选择全局渲染,这意味着网站的每一面(包括首页)都会加载 KaTex 相关的资源。(即使不存在任何 LaTeX 语法)这包括好几个 JavaScript 代码,一些 CSS 样式表,以及很多字体文件。但是对于我来说,可能网站需要渲染 LaTeX 的文章占比很低,全局渲染势必会造成资源浪费,拖慢网站的整体开启速度。

因此,我选择使用 Typecho 的自定义字段来手动判定页面是否需要渲染 LaTeX 语法。

教程开始

由于我发现自定义字段的值无法被 Typecho 插件获取,于是我们只能修改主题文件来实现。

使用 KaTeX

KaTeX自动渲染文档地址: https://katex.org/docs/autorender.html

在主题header.php文件内添加:

<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" />
<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
为了避免可能存在的渲染阻塞问题,我们可以引入defer关键字,可以参考相关官方文档获取更多有关阻塞的相关信息。

在主题footer.php文件内添加:

<script type = "text/javascript" >
  document.addEventListener("DOMContentLoaded", function() {
    renderMathInElement(document.body, {
      delimiters: [{
          left: "$$",
          right: "$$",
          display: true
      }, {
          left: "$",
          right: "$",
          display: false
      }],
      ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code"],
      ignoredClasses: ["nokatex"]
    });
  });
</script>

如需使用七牛云CDN加快访问速度,则将header.php内容改为:

<script defer type="text/javascript" src="https://cdn.staticfile.net/KaTeX/0.16.9/katex.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.staticfile.net/KaTeX/0.16.9/katex.min.css" />
<script defer type="text/javascript" src="https://cdn.staticfile.net/KaTeX/0.16.9/contrib/auto-render.min.js"></script>

2024年06月更新:

受org域名备案影响主域名更新为 staticfile.net , org老域名不再维护请用户尽快更换为net。

footer.php与上方配置相同,保持不变。

我们至此只做到了全局渲染,因此我们需要获取一些自定义字段内的值来判断是否需要添加 KaTeX。

按需渲染 LaTeX

为了避免手动输入自定义字段,我们需要增加一个自动绑定的输入框。打开主题的 functions.php ,填入如下函数:

function themeFields($layout) {
    $isLatex = new Typecho_Widget_Helper_Form_Element_Radio('isLatex', 
    array(1 => _t('启用'),
    0 => _t('关闭')),
    0, _t('LaTeX 渲染'), _t('默认关闭增加网页访问速度,如文章内存在LaTeX语法则需要启用'));
    $layout->addItem($isLatex);
}

修改header.php文件,为其添加判定逻辑:

<?php if ($this->is('post') && $this->fields->isLatex == 1): ?>
<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" />
<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
<?php endif; ?>

修改footer.php文件,为其添加判定逻辑:

<?php if ($this->is('post') && $this->fields->isLatex == 1): ?>
<script type = "text/javascript" >
  document.addEventListener("DOMContentLoaded", function() {
    renderMathInElement(document.body, {
      delimiters: [{
          left: "$$",
          right: "$$",
          display: true
      }, {
          left: "$",
          right: "$",
          display: false
      }],
      ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code"],
      ignoredClasses: ["nokatex"]
    });
  });
</script>
<?php endif; ?>

这样修改后,只有当页面为文章且文章内的自定义字段LaTeX选项为开启时,才会加载 KaTeX 渲染库。

参考