As it turns out, adding support to render LaTeX in a Jekyll blog isn’t all that hard, because other people have done most of the heavy lifting. There are two main ways to do this:
- Client-side rendering: After the page loads, a JS script is run to transform LaTeXy parts of the page to lovely, styled HTML.
- Build-time rendering: After Markdown files are compiled to HTML, a Jekyll plugin further transforms those LaTeXy parts to HTML as well. Here’s how you do either using .
Client-Side
Inside of your HTML <head>
tag, usually in _layouts/default.html
for Jekyll blogs, add the following to conditionally load stylesheets and scripts.
{% if page.katex %}
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.css"/>
<!-- JavaScript -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@latest/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body,{
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '$', right: '$', display: false },
{ left: '\\[', right: '\\]', display: true },
{ left: '\\(', right: '\\)', display: false }
]});">
</script>
{% endif %}
This uses jsDelivr as the CDN to deliver the styles and scripts; replace latest
in the URLs if you want to stick to a specific version. It uses KaTeX’s auto-render extension to render everything within the specified delimiters. display: true
is equivalent to a displaymath
environment, while display: false
is equivalent to an inline math
environment. Their documentation has a few more options you can set, like which tags and classes to ignore during processing.
To use LaTeX in a post, add katex: true
to the front matter, and write your LaTeX within the specified delimiters. For instance, the body of the following:
---
layout: post
title: "Your Post Title"
katex: true
---
This is an example of inline \\(\LaTeX\\). The following is Stokes' theorem in a
`displaymath` environment: \$$\int_{\partial \Omega} \omega = \int_{\Omega} d\omega\$$
is displayed as below:
This is an example of inline . The following is Stokes’ theorem in a
displaymath
environment:
Note the extra backslashes to escape \
and \$
from being processed by kramdown. Sometimes you will need to escape underscores as well to prevent kramdown from rendering text as italics instead of subscripts: the double subscript is written as \$\_{i\_{j}}\$
.
Build-Time
Your LaTeX can be rendered during Jekyll’s build instead of on the client side by using the jekyll-katex plugin. Note that this will not work with GitHub Pages because they only allow supported plugins. The plugin repository has a detailed README, but to setup in short:
- Add to
_config.yml
.plugins: - jekyll-katex
- Add to
Gemfile
.group :jekyll_plugins do gem "github-pages" gem "jekyll-katex" end
- Again, add stylesheet to
<head>
(conditionally, if you like).{% if page.katex %} < link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.css" /> {% endif %}
You should probably replace latest
with the version that the plugin comes with. It will only render LaTeX within specific Liquid tags. The example above can be written as:
This is an example of inline {% katex %}\LaTeX{% endkatex %}.
The following is Stokes' theorem in a `displaymath` environment:
{% katex display %}\int_{\partial \Omega} \omega = \int_{\Omega} d\omega{% endkatex %}
This is an example of inline . The following is Stokes’ theorem in a
displaymath
environment:
Or using the mixed math environment:
{% katexmm %}
This is an example of inline $\LaTeX$. The following is Stokes' theorem in a
`displaymath` environment: $$\int_{\partial \Omega} \omega = \int_{\Omega} d\omega$$
{% endkatexmm %}
There is no need to escape any special characters, aside from \$
to actually represent a dollar sign.
However, there doesn’t seem to be a way to customize the delimiters used in katexmm
.
The katex
and katexmm
Liquid tags can be ignored as usual, by wrapping content in {% raw %}{% endraw %}
tags.
Note also that they do not render when added to the front matter, such as in the title.
GitHub Pages GitLab Pages
Build-time rendering doesn’t work for GitHub Pages since they have a fixed set of Jekyll plugins.
On the other hand, it will work for GitLab Pages, since the site generation is part of a CI pipeline.
To port to GitLab, add the following to .gitlab-ci.yml
.
image: ruby:2.7
pages:
script:
- apt-get update && apt-get -y install nodejs
- gem install bundler
- bundle install
- bundle exec jekyll build -d public
artifacts:
paths:
- public
If you use Ruby 3 instead, you will need to add webrick
to your Gemfile
(see issue #8523 for the Jekyll repo).
group :jekyll_plugins do
gem "webrick"
gem "github-pages"
gem "jekyll-katex"
end
References
- Auto-render plugin for : https://katex.org/docs/autorender.html
jekyll-katex
plugin: https://github.com/linjer/jekyll-katex/- Jekyll plugins supported by GitHub: https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll#plugins
- GitLab Pages tutorial: https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_from_scratch.html