MathJax Greek Workaround

MathJax's Greek Characters

When I first started using MathJax to write equations in Obsidian, I was surprised to see that Greek letters didn't work like Latin ones! There were two major differences:

  1. Uppercase Greek letters were "upright / roman" by default, rather than italic.
  2. Lowercase Greek characters were unaffected by the commands \mathrm, \mathbf, \mathbfit, and similar. (\boldsymbol did work, though!)

Greek_Char_MathJax_Wrong.png|centred|360
The standard rendering of Greek characters.

I tried looking for workarounds online, but they were all quite complicated, and required macros or other features that I couldn't implement in Obsidian. I spent a few years just accepting that there was no solution, but I have now found something that works!

Greek_Char_MathJax_Correct.png|centred|360
The same commands after implementing my workaround.

The Workaround

The key realisation I had that makes this workaround possible is that Unicode Greek characters do behave identically to the Latin ones! While \mathrm \alpha is still italic, amazingly \mathrm α is upright! So we just need to redefine \alpha to write α instead. If you already know how to do this, you can skip the explanation below (but may want to look at part 3).

Part 1 — Adding a Preamble to MathJax

Firstly, you're going to need the Extended MathJax Plugin. This will let you add a so-called LaTeX Preamble to Obsidian's MathJax. This preamble allows you to define custom commands you can use in your notes! Defining custom commands is one of the most amazing parts of LaTeX, and I highly recommend it general (not just for this workaround).

Once you have installed the plugin, you need to create a preamble.sty file. By default, this should be in the root directory of your vault, but you can put it anywhere — just change the path in the plugin's settings.

Tip

If you haven't already, make sure you have "see file extensions" enabled in the file explorer you use. This will allow you to make, for example, a text file and then change the extension to .sty.

Part 2 — Redefining the Commands

Now that we have access to a preamble, we can go ahead and redefine the commands we want. You can copy-paste the commands from below for a quick solution, but again I highly recommend learning how to use \newcommand and \renewcommand in general.

Note that I also defined some commands for uppercase Greek letters that otherwise don't have any, like \Alpha and \Beta. You can remove these if you don't want them (they are the ones using \newcommand instead of \renewcommand).

Tip

If you want, you can also define some "shorthands" at this stage. I defined \ups and \eps for upsilon and epsilon respectively.

I have also defined \Delt for an "upright / roman" Delta, since differences like Δx shouldn't be italicised. \Sigma and \Pi don't have issues because \sum and \prod are unaffected by our changes.

Now simply save the file and restart obsidian. So long as the plugin is enabled, this should now work! The commands now behave consistently for \mathrm, \mathbf, \mathbfit, \mathsf, \mathsfbf, and \mathsfbfit. Uppercase \mathtt also works.

Strangely, \mathsfit still doesn't work on lowercase Greek at this stage, but that's addressed in part 3.

Part 3 — CSS and fonts

If you're ready to do some slightly more technical work, you can actually go even further than we have so far! Specifically, you can change the font that Obsidian uses to render MathJax using CSS snippets.

The default font is Computer Modern, designed by Donald Knuth. It's a lovely font, and it's been the standard 'mathematical / technical' font for quite some time. However, I personally didn't like the upright Greek lowercase (it has highly variable line width, being more "script-like" than I'd prefer). It's also missing many glyphs, like monospace Greek lowercase (even though uppercase is included).

Eventually I found the New Computer Modern font, which expands the selection of characters you can use immensely! It includes lowercase Greek monospace as part of its monospace variant, so I added a snippet to use it:

mjx-utext[variant="monospace"] {
    font-family: 'MJXZERO', 'MJXTEX-T', 'NewComputerModernMono10', monospace !important;
}

Resulting in this:

NewCM-Greek-Monospace.png|centre|420
Notice that the lowercase (from New Computer Modern) and uppercase (from Computer Modern) even match in width! New Computer Modern lives up to its name.

I also went ahead and set New Computer Modern and Cambria Math as the backup fonts for Unicode symbols:

mjx-utext {
    font-family: 'MJXZERO', 'MJXTEX', 'NewComputerModernMath', 'Cambria Math' !important;
}

This means I can use symbols such as ⤊ U+290A upwards-triple-arrow and it renders in the same style as the arrow given by \Rrightarrow (which, by default, has no \Uuparrow counterpart)!

New Computer Modern also has better upright Greek lowercase, since it just "un-italicises" the italic versions. However, I still found this slightly unsatisfactory, preferring the glyphs from Cambria Math. Here, however, I ran into a problem:

mjx-utext[variant='normal'] { /* This is actually upright, not \mathnormal */
    font-family: 'MJXZERO', 'MJXTEX-RM', 'Cambria Math', 'NewComputerModernMath', serif !important;
}

The snippet above works, yes, but it means that all Unicode characters after \mathrm will default to Cambria Math (if there's no default glyph in MJXTEX-RM), even though I only want that for Greek Lowercase. If I use, say, þ or ß, I still want to use New Computer Modern! The solution came in the form of the unicode-range CSS descriptor, which let me define a modified version of Cambria Math with only Greek characters!

@font-face {
    font-family: "My-Cambria-Greek";
    src: local("Cambria Math");
    unicode-range:
        U+0131, U+0237, /* Dotless i & j */
        U+0370-03FF, /* Greek */
        U+1D6A8-1D7C9, /* Math Greek */
        U+03DC, U+03DD, U+1D7CA, U+1D7CB /* Digamma */
    ;
}

I then added this modified font to the CSS rule from earlier:

mjx-utext[variant='normal'] { /* This is actually upright, not \mathnormal */
    font-family: 'MJXZERO', 'MJXTEX-RM', 'My-Cambria-Greek', 'NewComputerModernMath', 'Cambria Math', serif !important;
}

Which now only affects the relevant Greek characters! I did a similar thing for \mathbb, since I didn't like the numerals and lowercase Latin given by New Computer Modern:

@font-face {
    font-family: "My-Cambria-Bb";
    src: local("Cambria Math");
    unicode-range:
        U+1D538-1D56B, /* Latin */
        U+1D7D8-1D7E1 /* Numbers */
        ;
}

And then the rule:

mjx-utext[variant='double-struck'] {
    font-family: 'MJXZERO', 'MJXTEX', 'My-Cambria-Bb', 'NewComputerModernMono10', monospace !important;
}

You can use the same pattern to select for other stylistic variants, and use whatever font you like. Sometimes there are issues with letter-spacing, but these might be fixable through other settings applied via @font-face.

Use the inspect element pane (Ctrl+Shift+I) to figure out what names the variants have and what their default fonts are. Keep in mind there's a difference between Unicode text and TEX text. For example, to fix italic sans-serif lowercase Greek (which was mentioned as not working earlier), I needed this rule:

mjx-mi.mjx-ss.mjx-i > :is(mjx-c.TEX-SSI, mjx-c.TEX-I, mjx-utext[variant='sans-serif-italic']) {
    font-family: 'MJXZERO', 'MJXTEX-SSI', 'NewComputerModernSans10', sans-serif !important;
    font-style: italic;
}

You can probably get rid of the mjx-mi and mjx-c, but I haven't tried. If you're new to CSS, keep in mind that .x.y is different from .x .y — the first selects for objects with classes .x and .y, while the second selects for objects .y contained (at any level) by an object with class .x (if you use .x > .y then .y must be directly contained in .x).

Below you can find the full snippet (as of the time of writing, my snippets are constantly being worked on).

It might be possible to make \mathcal or \mathscr work for Greek using this method, which I’ve attempted using the Talos Font. I haven't gotten a result I'm happy with yet, but someone with more knowledge of CSS (or the ability to modify fonts properly) might be able to succeed.

Conclusion

While this workaround is certainly a bit "hacky", the solutions I saw online are often worse, and didn't work for Obsidian (since they rely on commands we can't used in the preamble). It's possible this method is already known of, but I haven't seen it before, so I thought it good to share in the hopes I might help others looking for a solution, like I was a few years ago!

Appendix

Thanks for reading, and have a nice day!

Related Pages

A lonely page, it seems...