在Hugo中使用MathJax
2018-03-28 18:45:13 +08 字数:1987 标签: Hugo Markdown有时候,会有需要在网页中展示数学公式。 与代码高亮不同,Hugo本身是不支持渲染数学公式的。 因此,只能用前端的方式实现。
在已经生成好的HTML页面中,使用JavaScript来渲染LaTeX形式的数学公式,是一个可行思路。 MathJax是这方面最流行的JavaScript库。
官方文档的MathJax使用方案有一些问题,本文提供的方案胜于官方。
MathJax简介 ¶
MathJax是一个开源的JavaScript数学公式渲染引擎,支持LaTeX、MathML、AsciiMath等形式的数学公式,并且适配所有现代的浏览器。
A JavaScript display engine for mathematics that works in all browsers.
No more setup for readers. It just works.
测试样例 ¶
与代码类似,数学公式也有有行内(inline)公式和区块(block)公式。 前者需要与同行的其它文字混排,而后者需要独占一行,居中显示。 以下展示了两个行内公式和一个区块公式的测试代码,可以放到Markdown中测试MathJax的渲染效果。
When $a \ne 0$, there are two solutions to $ax^2 + bx + c = 0$ and they are:
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}$$
When $a \ne 0$, there are two solutions to $ax^2 + bx + c = 0$ and they are:
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}$$
方案 ¶
这里给出两个方案,分别是官方方案与本站实际使用的自定义方案。
官方方案与改进 ¶
官方方案有三处修改,其实添加第一处,引入MathJax就已经可以支持区块公式了。
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
但是,这样对行内公式仍然无法支持。
而除了支持行内公式,还有Markdown特殊字符的转义问题,如下划线_
。
为了支持无需转义地写公式,行内公式推荐写成行内代码,用``
来包含,而区块公式则推荐用<div></div>
来包含。
例如:
When `$a \ne 0$`, there are two solutions to `\(ax^2 + bx + c = 0\)` and they are:
<div>$$
x = {-b \pm \sqrt{b^2-4ac} \over 2a}
$$</div>
而为了解决样式问题,把普通的code
与MathJax分开,官网使用了加后缀的方式。
根据《MathJax in Markdown - Doswa》提供的方法,把MathJax的code
样式自动改成code has-jax
。
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
displayMath: [['$$','$$'], ['\[','\]']],
processEscapes: true,
processEnvironments: true,
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
TeX: { equationNumbers: { autoNumber: "AMS" },
extensions: ["AMSmath.js", "AMSsymbols.js"] }
}
});
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Queue(function() {
// Fix <code> tags after MathJax finishes running. This is a
// hack to overcome a shortcoming of Markdown. Discussion at
// https://github.com/mojombo/jekyll/issues/199
var all = MathJax.Hub.getAllJax(), i;
for(i = 0; i < all.length; i += 1) {
all[i].SourceElement().parentNode.className += ' has-jax';
}
});
</script>
上面两段JavaScript就是官网第二处修改。
前者做了一些配置,而后者就是自动给className
加 has-jax
后缀。
而后,下面的第三处修改,则是在CSS中对这种特殊的MathJax进行样式处理,否则行内公式的显示会有些奇怪。
code.has-jax {
font: inherit;
font-size: 100%;
background: inherit;
border: inherit;
color: #515151;
}
然而,这样做亲测无效! 祝你好运!
本站方案(note.qidong.name) ¶
本站在添加MathJax时,把所有修改写成了一个layouts/partials/mathjax.html
文件:
<script type="text/javascript"
async
src="https://cdn.bootcss.com/mathjax/2.7.3/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
displayMath: [['$$','$$'], ['\[\[','\]\]']],
processEscapes: true,
processEnvironments: true,
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
TeX: { equationNumbers: { autoNumber: "AMS" },
extensions: ["AMSmath.js", "AMSsymbols.js"] }
}
});
MathJax.Hub.Queue(function() {
// Fix <code> tags after MathJax finishes running. This is a
// hack to overcome a shortcoming of Markdown. Discussion at
// https://github.com/mojombo/jekyll/issues/199
var all = MathJax.Hub.getAllJax(), i;
for(i = 0; i < all.length; i += 1) {
all[i].SourceElement().parentNode.className += ' has-jax';
}
});
</script>
<style>
code.has-jax {
font: inherit;
font-size: 100%;
background: inherit;
border: inherit;
color: #515151;
}
</style>
这里,把官网的三处修改合并成一个partial。
此外,还把MathJax的CDN从cdnjs.cloudflare.com
替换成了cdn.bootcss.com
,更好地支持国内。
因为个人的一些写作习惯,还替换了区块公式的第二标志,从中括号[]
换成双中括号。
把这个partial模板添加到<head>
中,即可正常工作。
{{ partial "mathjax.html" . }}
本站新方案(2020年更新) ¶
为了与时俱进,本站新方案使用v3版本。
{{ if .Params.math }}
<script>
MathJax = {
tex: {
inlineMath: [["$", "$"]],
},
displayMath: [
["$$", "$$"],
["\[\[", "\]\]"],
],
svg: {
fontCache: "global",
},
};
</script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script
id="MathJax-script"
async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
></script>
{{ end }}
以上是新的mathjax.html
方案,使用的是最新的v3版本,保持更新。
还额外加上了.Params.math
的检查,避免所有页面都需要加载它。
在需要使用的Hugo页面,可以在Front Matter中添加一个配置,显式指定使用Mathjax。
以下为TOML形式的示例:
+++
...
math = true
+++
(c)(r)等转义问题 ¶
在Hugo使用blackfriday
的情况下,(c)
可转换为©,(r)
可转换为®。
$$
AveP = \int_0^1 p(r) dr
$$
于是,以上公式会转义,发生显示问题。
以上提到的<div>
方案,是可以解决这个问题的。
此外,要禁用全局的这种转义,也可以在config.toml
中添加以下配置,禁用该功能。
[blackfriday]
smartypants = false
效果如下:
$$ AveP = \int_0^1 p(r) dr $$
如果是使用goldmark
,则无上述问题。
Hugo的v0.60.0版本后,默认使用goldmark
。
参考 ¶
官网的《Enable MathJax》,是绝佳的参考,但有上述问题。
此外还有中文版的《MathJax Support - Hugo中文文档》,基本是官网内容的翻译,不过内容略有滞后,比如CDN代码仍然是cdn.mathjax.org
的,不推荐使用。
另外还有一篇《Setting MathJax with Hugo | Hi, I am David》,其中解决了MathJax.Hub.Queue
那段JavaScript的问题。
本站的方案,受益于此。