Syntax highlighting and maths without Javascript

Published on 2023-10-23.

This website runs only with a very limited amount of Javascript. Despite its bare bones appearance, it still provides syntax highlighting for code snippets and nicely formatted math equations. This post describes the relatively simple process I go through to achieve such a result.

Syntax highlighting

Code syntax highlighting relies on the pygmentize command-line tool. pygmentize provides access to the Pygments syntax highlighter, which supports a wide variety of languages. Most importantly, it support outputting highlighted code as an HTML file by relying on a small CSS file to provide color definitions.

Let's try on a simple example. We will use the following C file and convert it to highlighted HTML.

#include <stdio.h>

int main(void) {
    puts("Hello world!");
    return 0;
}

The first step is to generate the HTML code using pygmentize. To achieve this, simply run the following command.

pygmentize main.c -o main.html

The output file should look like the following.

<div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span>

<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="n">puts</span><span class="p">(</span><span class="s">&quot;Hello world!&quot;</span><span class="p">);</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>

The cp, w, cpf, etc., classes are used by Pygments to provide highlighting groups for the code. We can retrieve the CSS definition of these classes for any of the numerous highlighting themes provided by Pygments using the following command.

pygmentize -f html -S <theme-name> # This website uses the 'default' theme

The resulting CSS file can then be added to your website, et voilĂ ! You should now have highlighted code that looks like the first snippet on your static HTML web page.

Note: You can add a prefix to all the CSS classes by adding -a .your_prefix to the preceding command and to the pygmentize highlighting command.

Math typesetting

LaTeX-style math typesetting is often achieved through the use of Javascript rendering engines such as MathJax or KaTeX. However, it is possible to achieve the same kind of rendering quality without reaching for JS by leveraging SVG vector images and a locally-installed LaTeX toolchain. As an example, the following equation was produced by the method described in the remainder of this section.

Gaussian integral

We can leverage the standalone LaTeX document class to produce self-contained documents that contain only a single equation. Here is the template I use for all the equations on this website.

\documentclass[preview]{standalone} % preview is required for display math

\usepackage[utf8]{inputenc}

\usepackage{amsmath,amsfonts,amssymb}

\begin{document}

\[
    % Gaussian integral example
    \int_{-\infty}^{+\infty}e^{-x^2}\mathrm{d}x=\sqrt{\pi}
\]

\end{document}

This template can then be processed by latex to produce a DVI file, which can be converted to an SVG image using dvisvgm as follows.

latex template.tex
dvisvgm -fwoff2 -c 1.5 template.dvi

The template.svg image can then be embedded in a static web page like a regular image, or you can directly embedded it using inline SVG.

Note: The -c option scales the output by the given factor. I have found that 1.5 produces the nicest output for the font size I am using. Your mileage may vary, so test a few scaling factors to see which one fits best.

Warning: The -fwoff2 flag selects WOFF2 fonts instead of the default fonts. Without this option, rendering may not look quite right, especially when using maths symbols. It should be quite safe to use with most modern browsers, but if you aim for greater compatibility you can select regular WOFF as well.