SVGMath overview
Explanation
SVGMath is a way to produce good looking math on the Web, without using the javascript-based approaches of MathJax or KaTeX. It's an SVG-based approach to fast loading of beautiful math on the Web.
See the SVGMath demo page .
SVGMath is a proof-of-concept attempt at solving the following issues when displaying math on the Web:
- MathJax and KaTeX are javascript-based libraries that convert LaTeX (or MathML) to attractive mathematics for easy reading
- Being javascript based, it takes time for the javascript to load, and takes even more time to process and display the math. While developers of both libraries have put a lot of effort into making things as fast as possible, users are impatient when pages take a long time to load and will tend to abandon them. There's a search engine penalty for slow sites as well.
- Most sites already have a large volume of "javascript soup" (including libraries like JSNode, jQuery, etc, and/or advertising, social network widgets, and so on). All of this soup competes with each other as the page loads, slowing everything down.
- Both MathJax and KaTeX libraries produce a huge number of HTML elements (
<span>
s, mostly) that are necessary to display the math properly. Such DOM creation and manipulation is a big reason why loading and processing take so long. Page analysis tools like Lighthouse complain bitterly about page load blocking and the large number of DOM elements on such pages. - Both libraries provide MathML output for accessibility reasons (blind people can make use of MathML for exploring within math and copying portions). This adds to the large number of DOM elements created.
So this page is an attempt to address some of the above items.
- There is no javascript used at all for equation processing on page load (except some sizing tweaks for narrow screens)
- We're embedding SVGs only, and doing it using "lazy loading" (so the browser only loads the SVGs as the user scrolls down to them).
- In 2 out of the 3 output versions, the SVGs use
<text>
tags instead of<path>
s for all numbers and variables. This makes each SVG considerably smaller, since we call the fonts once on page load (and don't draw a picture of each character, like in<path>
s). - SVGMath includes screen reading facilities (
aria-label
s) but not MathML by default, since the majority of browsers doesn't handle MathML yet, and this keeps the page smaller. (Try the demo page with a screen reader.) - Equation tags (numbering) successfully appear if
\label{...}
is present in the equation, and links to those numbered equations also work.
How it's done
- The page is processed on the server (by PHP) so it's complete before it appears in the user's browser. It works somewhat similarly to a Wordpress plugin, where the LaTeX equations on the page are replaced by math.
- In the development phase for a page, all the
\begin{equation} ... \end{equation}
,$$... $$
,$ ... $
, etc are replaced with a call to MathJax-SVG, and each equation in SVG form is written to the server. - Once the SVGs exist on the server, they are lazy-load added to the page using AJAX (or in the image case, actually lazy loaded). The SVGs are cached and don't need to be created again.
- For the demo, I created 3 versions:
- Inline SVG, using
<text>
tags and with fonts called (once) in the HTML<tag>
tag, loaded using my own lazy loader - SVGs using
<text>
tags this time embedded in<object>
tags, which require a call to the fonts in each equation, once again loaded using my own lazy loader - SVGs using
<path>
tags this time called in<img>
tags, and loaded usingloading="lazy"
- Inline SVG, using
- Any equation tags are extracted and added as a <span> on the far right of the equation.
- Any tag links are kept track of by arrays and the
\eqref
are converted to links and point to the correct equation. - Of course, the whole thing is phone-friendly
Accessibility
Rather than load accessibility elements for everyone, SVGMath includes enough information for a screen reader to produce spoken math, derived from MathJax's screen reader text ooutput.
Try the page using a screen reader to hear the result.
(If equation exploration and copying facilities are required, it makes more sense to use MathJax or KaTeX.)
Comparison Stats
There are different versions of SVGMath here for comparison with each other, and with MathJax and KaTeX. The stats given here are roughly what I saw in my environment. There are many variables and your mileage will differ.
Lighthouse is the performance analysis tool within Chrome development tools. Total blocking time is how long we have to wait for the javascript to download and do its thing before anything else can happen - lowest is best, of course. The Speed index is a metric that compares a page's performance to the Web in general (a value between 0 and 3.4 s on a phone is regarded as "fast").
All of the methods listed here make use of lazy loading of the math, so that initial page load is as fast as possible. (MathJax has a native lazy load option which I'm using here, while KaTeX does not, so I'm using my own implementation.)
Cells with green background are the best, red is worst.
NOTE: For each of MathJax and KaTeX in the tables below, we are processing the math on the client side. For SVGMath, by design, no client-side script is used for the math.
(1) Inline <svg>s using <text> tags
This is the best version for performance. The resource use is low and the number of DOM elements is roughly 1/3 of those produced by MathJax or KaTeX.
We're using <text> tags for numbers and variables, rather than <path>s (which is what MathJax uses in its SVG version.) We're also using a simple <span> element (not a whole SVG) for the very simple (one-character) math items (like "x") where it's overkill to use an antire SVG.
One downside of this technique is it's not so good for SEO (search engine optimisation) as the SVGs are embedded, not existing as a separate file, so they never appear as separate entities in search results. However, given that speed is one of Google's key metrics for search performance, it's a price worth paying.
SVGMath <svg> |
MathJax HTML |
MathJax SVG |
KaTeX | |
---|---|---|---|---|
On initial load | ||||
DOM elements | 419 | 97 | 97 | 97 |
kB transferred | 91.4 | 331 | 736 | 250 |
kB resources | 152 | 1,300 | 2,500 | 797 |
Finished processing | 0.172 s | 0.539 s | 0.783 s | 0.340 s |
Fully loaded and processed (scrolled to bottom of page) |
||||
DOM elements | 4089 | 9,495 | 9,074 | 12,248 |
kB transferred | 250 | 352 | 736 | 259 |
kB resources | 503 | 1,300 | 2,500 | 805 |
Lighthouse performance score | 100 | 89 | 87 | 88 |
Total blocking time | 0 s | 0.490 s | 0.560 s | 0.170 s |
Speed index | 1.0 s | 1.3 s | 1.7 s | 1.9 s |
(2) SVGs within <img> tags
Calling the SVGs in <img> tags produces the same low number of DOM elements (1/20 or less than the others) as <object>s.
However, we've had to use <path>s for all elements in the math (numbers and variables as well), since any <style> tags in the main page that target the SVG are ignored when called from an <img> tag. So the resource load is greater than the embedded SVG case (by about twice).
A downside to using <img>s like this is that they aren't searchable on the page, whereas <svg> tags that use <text> are.
SVGMath <img> |
MathJax HTML |
MathJax SVG |
KaTeX | |
---|---|---|---|---|
On initial load | ||||
DOM elements | 484 | 97 | 97 | 97 |
kB transferred | 147 | 331 | 736 | 250 |
kB resources | 327 | 1,300 | 2,500 | 797 |
Finished processing | 0.089 s | 0.539 s | 0.783 s | 0.340 s |
Fully loaded and processed (scrolled to bottom of page) |
||||
DOM elements | 484 | 9,495 | 9,074 | 12,248 |
kB transferred | 424 | 352 | 736 | 259 |
kB resources | 1,100 | 1,300 | 2,500 | 805 |
Lighthouse performance score | 100 | 89 | 87 | 88 |
Total blocking time | 0 s | 0.490 s | 0.560 s | 0.170 s |
Speed index | 1.0 s | 1.3 s | 1.7 s | 1.9 s |
(3) (Historical) SVGs within <object> tags
NOTE: Earlier, I had a version that used <object> tags. It proved to be unsatisfactory because the user experience was "clunky" (especially on a phone) as the math fonts have to be loaded for every <object>. Overall, I now feel the image tag approach is best.
The number of DOM elements required was least when using <img> or <object> tags (since we only require 2 for each piece of mathematics - a wrapper span and the one tag).
I was using <text> tags in the SVG once again (to keep things as small as possible), but the downside is that the fonts need to be called in every SVG embedded this way. Browsers aren't bright enough to remember they've already accessed the font (even though Chrome's developer tools indicate the font is coming from the cache) so "download" it for each math item. So it indicates a huge resource load (6.8 MB) where in fact, the fonts should only be loaded once.
The number of DOM elements was about 1/20 of MathJax's and KaTeX's when using <object>s.
This method also was problematic for SEO, so all round, best abandoned.
Finally
The content for the SVGMath demo page was chosen because it has many equations, and label tags (equation numbering), and links to tags (which MathJax can handle, and KaTeX cannot yet, but my version does).
The best overall solution appears to be +using inline <svg>s within which <text> tags are used for any ASCII characters.