janmr blog

Wrapping HTML inside MathML

MathML is a mathematical markup language that can be used to integrate math into web pages. For example,

<math display="block">
  <msqrt>
    <mn>1</mn>
    <mo>+</mo>
    <msup>
      <mi>x</mi>
      <mn>2</mn>
    </msup>
  </msqrt>
</math>

which would produce

Unfortunately, browser support is far from great (and not as good as caniuse.com reports).

What people do instead is use libraries such as MathJax which can replace the math container with the appropriate HTML, either server-side or client-side.

However, putting math markup in a structured way inside math elements has many advantages, such as accessibility and search engines.

So let's put the HTML inside the math element instead, alongside the MathML. MathML has a feature which makes it possible to include “alternate representations of an expression”. These alternate representations are put inside annotation or annotation-xml blocks. The example above could look like

<math display="block">
  <semantics>
    <msqrt>
      <mn>1</mn><mo>+</mo><msup><mi>x</mi><mn>2</mn></msup>
    </msqrt>
    <annotation encoding="application/tex">
      \sqrt{1 + x^2}
    </annotation>
    <annotation-xml encoding="text/html">
      <span class="mjx-chtml MJXc-display" style="text-align: center;">
        ...
      </span>
    </annotation-xml>
</math>

This will not display properly out-of-the-box, but Chrome's current user agent stylesheet comes close:

math {
    display: inline;
}

math[display="block"] {
    display: block;
    text-align: center;
}

semantics &gt; mi, semantics &gt; mn, semantics &gt; mo, semantics &gt; mtext, semantics &gt; mspace, semantics &gt; ms, semantics &gt; maligngroup, semantics &gt; malignmark, semantics &gt; mrow, semantics &gt; mfrac, semantics &gt; msqrt, semantics &gt; mroot, semantics &gt; mstyle, semantics &gt; merror, semantics &gt; mpadded, semantics &gt; mphantom, semantics &gt; mfenced, semantics &gt; menclose, semantics &gt; msub, semantics &gt; msup, semantics &gt; msubsup, semantics &gt; munder, semantics &gt; mover, semantics &gt; munderover, semantics &gt; mmultiscripts, semantics &gt; mtable, semantics &gt; mstack, semantics &gt; mlongdiv, semantics &gt; maction {
    display: none;
}

annotation, annotation-xml {
    display: inline-block;
}

If a semantics element is present it will not show the (presentation) MathML markup, but instead show all annotation blocks.

This is a bit too accepting, but if we replace the bottom three lines with the following, then exactly the right annotation-xml blocks will be visible:

annotation, annotation-xml {
    display: none;
}

annotation-xml[encoding="text/html"] {
  display: inline-block;
}

Browser support for this seems to be good, with the exception of Safari.

You can experiment with a codepen example and the css can be found as a GitHub gist.