A Technical Introducition to MathML Core for Writing Mathematics on the Web
- Programming, Mathematics
Latest revision:
Thanks to recent efforts, all major web browsers currently support MathML Core, a subset of MathML focused on important presentation markup, to support mathematics on the web. As of this writing, the MathML Core specifications are still not finalized, but given its strong origins and support, it can be used right now by web developers.
While the full version of MathML is relatively complex, MathML Core keeps almost all of its capabilities while being simple enough to directly code and read it without relying on external tools and renderers. In fact, I would highly discourage this practice, as said tools tend to generate valid code that may look correct but generally are unnecessarily complex and hide accessibility or other issues. Classic tools like TeX, LaTeX, MathType and MathJax are therefore no longer relevant in MathML Core.
Before writing this blog post, I took the time to completely re-write all of the mathematics on my website in MathML Core to fully understand its strengths and weaknesses, so feel free to browse my previous blog posts for examples such as the one where I explain how deep learning AI works.
The following is a technical introduction to MathML Core which assumes you have a basic understanding of Unicode and are familiar with general web development in HTML and CSS. While I will be referring to the ISO 80000-2 standard as well, knowledge of this standard is not required. Keep in mind that I have deliberately omitted several MathML Core elements, attributes and CSS properties from this document to focus exclusively on writing mathematical expressions as efficiently as possible.
Inheritance from other web specifications
HTML
Text in MathML Core is normal HTML flow content, and can therefore embed additional HTML and/or SVG elements in it.
CSS
MathML Core supports all normal CSS properties from HTML.
MathML Core implements additional CSS properties and/or values specific to its elements, but will not be detailed here as their knowledge is not generally helpful when writing MathML Core, and as non-web MathML parsers may not support CSS anyway.
Scripts
MathML Core is fully-compatible with normal client-side scripting.
Global attributes
class
, data-
*, dir
, id
, nonce
, on
* event handlers, style
, tabindex
attributes: Behaves the same way as for HTML elements.
displaystyle
attribute: By default, script sub-expressions are always rendered in compact style. This attribute overrides whether the expression should be rendered in normal or compact style. Possible values are true
for normal style, and false
for compact style.
scriptlevel
attribute: By default, a script sub-expression will appear slightly smaller than its direct parent if said direct parent is in compact style. This attribute overrides this behavior. Its value should be an integer. If the integer starts with a sign (+
or -
), the script level change is relative to its parent, otherwise the change is absolute, with 0
being the default top-level.
Important elements
<math>
The top-level element for MathML Core expressions.
Content: A MathML Core expression.
display
attribute: Determines if the mathematical expression should be rendered in compact style as inline text, or in normal style as a block. Possible values are inline
(default) and block
. Note that while this attribute is linked to the display
CSS property, it is not equivalent.
xmlns
attribute: No effect in modern web browsers. Note however that if the expression is to be exported outside of its HTML context, this attribute should be set to http://www.w3.org/1998/Math/MathML
.
<mtext>
Arbitrary text, generally for commentary.
Content: Normal text.
<mi>
An identifier, such as a function, variable or constant name, or a placeholder. If the contents of an identifier needs to be in a certain style to convey its proper meaning, the proper Unicode characters should be used instead of applying styles via CSS.
By default, for convenience, if this element contains a single character, said character is dynamically replaced with a corresponding italic variant during rendering if it is among a specific set. Generally speaking, this set compromises all normal modern plain Latin and Greek letters, the small dotless i and j letters, and a very small subset of Greek and calculus symbols.
Content: Normal text.
mathvariant
attribute: When present and set to normal
, the default automatic transformation of single characters to italic variants will not occur.
<mn>
A numeric literal. It doesn't matter if the contents is written in decimal, hexadecimal, binary, Japanese numerals, Roman numerals, plain English or some other representation, as long as said representation matches a value in a numeral system.
Content: Normal text. Generally however, this element should contain a nonnegative rational number in positional notation. Base 10 should also generally be used unless another base is more appropriate in context.
<mo>
This represents any of the following:
- An operator, such as a minus sign.
- A fence, such as a paranthesis.
- A separator, such as a comma.
- An accent, such as an horizontal bar over some other element.
The default rendering of this element is complex and changes depending on its content and whether it is the first and/or last element of its parent. For example, an <mo>
containing a single left curly bracket will be automatically stretched and will not have blank spaces around it if it is the first element in a group of multiple elements.
Content: Normal text. Generally however, this element should contain a single character.
lspace
, rspace
attributes: Sets the spacing on the left and right sides of this element, respectively. Possible values are any valid CSS length or percentage. Defaults can generally be summarized as follows, with lspace
first and rspace
second:
- 3/18 em, 0/18 em for roots and derivatives excluding normal Latin letters
- 0/18 em, 3/18 em for separators
- 0/18 em, 0/18 em for unitary operators, n-ary operators, fences and invisible operators
- 3/18 em, 3/18 em for distributive binary operators and integrals
- 4/18 em, 4/18 em for non-distributive binary operators
- 5/18 em, 5/18 em for everything else
symmetric
attribute: If this element would stretch vertically, its center will be aligned with the separators of sibling fraction-like elements. The value must be a boolean. Default is generally true
for fences and false
otherwise.
Note that this element has even more attributes specific to it to modify its rendering, but I will not be describing them here due to their niche uses.
<ms>
A string literal, as used in programming languages. This should be used only when the contents of this element is an actual mathematical value represented by an array of Unicode characters in some arbitrary character encoding form.
Content: Normal text. Surrounding quotes should generally be included.
<mrow>
Groups elements that are not implicitly grouped by another element, for sub-expressions. Unlike <div>
elements, this has an effect on rendering due to the way <mo>
elements are rendered within a group (refer to the <mo>
section for details) and as grouping determines how automatic line breaking should be applied when the available width is insufficient.
Content: A MathML Core expression.
<mfrac>
A fraction or fraction-like object, such as the inside of a binomial coefficient.
Content: The first element is the numerator, and the second element is the denominator.
linethickness
attribute: Changes the thickness of the line between the numerator and the denominator. Possible values are any valid CSS length or percentage. If this attribute is set to 0
, no line is drawn and the element behaves similarly to a 1x2 table.
<msqrt>
A radical without an index, generally used for square roots.
Content: The base of the root.
<mroot>
A radical with an index, such as a cube root.
Content: The first element is the base of the root, and the second element is the index of the root.
<msub>
An expression with a subscript, such as a number in a non-decimal base.
Content: The first element is the base, and the second element is the subscript.
<msup>
An expression with a superscript, such as a squared number.
Content: The first element is the base, and the second element is the subscript.
<msubsup>
An expression with both a subscript and a superscript, such as a derivative in Lagrange's notation of a numbered variable.
Content: The first element is the base, the second element is the subscript, and the third element is the superscript.
<munder>
An expression with an underscript, such as a limit.
Content: The first element is the base, and the second element is the underscript.
<mover>
An expression with an overscript, such as a complex conjugate.
Content: The first element is the base, and the second element is the overscript.
<munderover>
An expression with both an underscript and overscript, such as a sum with capital-sigma notation.
Content: The first element is the base, the second element is the underscript, and the third element is the overscript.
<mmultiscripts>
An expression with an arbitrary number of subscripts and superscripts including prescripts, such as a tensor.
Content: The first element is the base, and the following elements must be pairs of one subscript and one superscript, in that order. The <mprescripts>
element can optionally be added as a separator before or between a pair to indicate that the following pairs are prescripts. Pairs on each side of the separator must be added in reading order. If a pair does not require a corresponding subscript or superscript, an empty <mrow>
should be used as a placeholder.
<mprescripts>
A separator for the <mmultiscripts>
element. See its description for details.
Content: Should be empty.
<mtable>
A table of mathematical expressions, such as the inside of a matrix. Their format are similar to HTML <table>
elements.
Content: <mtr>
elements.
<mtr>
A row of mathematical expressions.
Content: <mtd>
elements.
<mtd>
A cell containing a mathematical expression.
Content: A MathML Core expression.
columnspan
, rowspan
attributes: Behaves the same way as for <td>
in HTML.
Tricky characters and typefacing
Obscure mathematical operators and symbols
If a specific mathematical character is hard to find via a search engine or other means, I recommend looking at the Mathematical operators and symbols in Unicode article on Wikipedia to find any specific one you may need.
Letter styles
Identifiers in a special style, such as bold, italic or double-struck, should generally directly use the character for these styles instead of applying styles via CSS. I recommend consulting the Mathematical Alphanumeric Symbols article on Wikipedia to determine which character correspond to the desired style for Latin and Greek letters, especially because the corresponding Unicode code points may not be in the expected order due to historical reasons.
One notable exception is when automatic italic is applied. See the description for the <mi>
element for details.
Non-standard character references
HTML and MathML contains the following character references that can be used as a substitute for their normal representation:
&CapitalDifferentialD
andⅅ
, which corresponds to ⅅ (U+2145).ⅆ
andⅆ
, which corresponds to ⅆ (U+2146).ⅇ
andⅇ
, which corresponds to ⅇ (U+2147).ⅈ
andⅈ
, which corresponds to ⅈ (U+2148).
Problem is, unlike what the name of these references suggest, these are not standard ways to write derivatives, Euler's number or the imaginary unit. These references appear to have been inherited from the Wolfram Language back when the original version of MathML was originally created instead.
According to the ISO 80000-2 standard, the normal Latin version of these characters (D, d, e and i) should be used in these cases instead.
Invisible characters
There are four invisible characters specifically designed for mathematical expressions:
- Function application (U+2061)
- Invisible times (U+2062)
- Invisible separator (U+2063)
- Invisible plus (U+2064)
The purpose of these characters is so that renderers, parsers and blind people can determine what operator is implied between two expressions without additional context. For example, it may be unclear to a reader if an integer followed by a fraction is supposed to represent a mixed fraction or a multiplication, or if two <mi>
s in a row is supposed to represent a sequence, a multiplication or a function with a single parameter.
These invisible characters should always be present in a MathML Core expression within <mo>
s whenever appropriate to mitigate such ambiguities.
If you have trouble working with invisible characters, for example if your IDE does not support showing such characters, you may use the following character references instead:
- Function application:
⁡
or⁡
- Invisible times:
⁢
or⁢
- Invisible separator:
⁣
or⁣
- Invisible plus:
ࠐ
In the case of the invisible function application operator, it should be applied in-between the function identifier and its parameter list. If the parameters are surrounded by fences, the operator should be placed outside of the fences. Note that this also applies to probability functions, including when its parameter is the description of an event. If you're unsure whether an invisible function application operator should be applied, it helps to consider if the relevant elements are already linked due to another element or not.
Mathematical symbol or not?
There are a bunch of Greek letters and punctuation that look like their mathematical counterparts, but aren't. The latter should be used when applicable for proper rendering and parsing. When in doubt, search for the character in the Unicode code charts to see if it refers to such a look-a-like.
In particular, the minus sign character – (U+2212) should generally be used instead of the hyphen-minus character - (U+002D) when used as the contents of an <mo>
, but the latter must be used when setting negative numerical attribute values to elements.
Non-trivial use cases
Blank space
There are multiple ways to perform this, including:
- Placing an
<mi>
containing no-break spaces or low line characters. - Placing an element containing some placeholder data, and set its
visibility
CSS property tohidden
.
Line breaks
Set an <mtable>
with the displaystyle
attribute to true
as the direct child of the <math>
element, with one <mtr>
containing a single <mtd>
per line.
2D elementary arithmetic
While it can be implemented with tables and lots of CSS trickery, 2D elementary arithmetic such as long division is not currently well-suited for MathML Core.
Truncated decimals with ellipsis
Use an <mn>
containing the part of the real number prior to the truncation, followed by an <mo>
containing an invisible plus, followed by an <mi>
containing the ellipsis. Optionally, also put an <mo>
containing the minus sign operator at the beginning of the expression if applicable. Place the entire expression inside an <mrow>
if appropriate.
Repeating decimals
While it can be implemented with invisible operators and lots of CSS trickery, numbers with repeating decimals are better represented in MathML Core as fractions, mixed fractions or infinite sums.
If a mixed fraction is used, it should include an invisible plus inside an <mo>
between the terms. Place the full expression inside an <mrow>
if appropriate.
Infinity
Infinity is not numeric, so an <mi>
should be used.
Constants
It may be tempting to use an <mn>
for constants like the Euler's number as they are real numbers, but an <mi>
should actually be used instead unless the actual digits of such constants are represented.
One common mistake, and especially in English publications, is that mathematical constants should NOT be rendered in italic, at least according to the ISO 80000-2 standard. Only variables should be in italic. Therefore, when an <mi>
element contains a single character representing such a constant, its mathvariant
attribute should be set to normal
when applicable. Note that this does not apply to physical constants or statistics, as they are technically variables derived from physical measurements.
Complex numbers
The real and imaginary parts of a complex number should be handled as separate elements, separated by a plus sign or minus sign <mo>
, and grouped within <mrow>
s if necessary. This should include an invisible times <mo>
within the imaginary part of the number, which itself should be wrapped in an <mrow>
due to operator precedence. A minus sign <mo>
should also be included in the real part prior to its numeric size if applicable. Place the full expression inside an additional <mrow>
if appropriate.
Once again, according to ISO 80000-2, the imaginary unit should use a normal i as its identifier, and because it is a mathematical constant, the mathvariant
attribute of the corresponding <mi>
should also be set to normal
so that it is not rendered in italic.
Single-letter function identifiers
Similar to variables vs. contants, ISO 80000-2 specifies that function identifiers with a universally-accepted definition should NOT be in italic, while other functions that change definitions depending on context should. In the former case, the mathvariant
attribute should be set to normal
when applicable on the relevant <mi>
s.
Either way, the invisible function application should be applied in an <mo>
in-between it and parameters if applicable. In this case, place the full expression inside an <mrow>
if appropriate.
Probability of an event
To denote the probability of an event in mathematical form, it is common to use the letter P followed by a description of the event in paranthesis. In such a case, P would be considered the probability function, and as such an <mi>
element should be used for it, followed by an invisible function application <mo>
, followed by an <mrow>
containing each paranthesis in separate <mo>
s. Place the full expression inside an additional <mrow>
if appropriate. For ISO 80000-2 conformance, the P should be in italic since the definition of the probability function depends on context.
In addition, when using text to describe the input event for the probability function, an <mtext>
should generally be used in-between the parantheses as the text is to be interpreted as itself, not as an array of Unicode characters.
Distance between points
When denoting the distance between two points with a small d identifier, since the concept of distance is a function, the above considerations about single-letter function identifiers applies. Also, since the distance function can be defined in various ways (Euclidian distance is generally assumed but is not guaranteed), the d should be in italic for ISO 80000-2 conformance.
Multiple subscripts in a row at the same script level
There are multiple solutions for this, including:
- Using an
<mmultiscripts>
with empty<mrow>
s as paired superscripts. - Using a single
<msub>
containing multiple elements separated by invisible separator<mo>
s. - In the case where each subscript represents a single digit, using a single
<msub>
containing a single<mn>
.
In the general case, the <mmultiscripts>
solution is preferred.
Workarounds
Calculus in Leibniz notation or D-notation
Due to a limitation in MathML Core, when using an <mo>
containing a single Latin capital or small D to represent a derivative, the default spacing is applied around the operator instead of the one for derivatives. To work around this, such an element can have its lspace
attribute set to 0.16666666666666666em
and its rspace
attribute to 0
to apply the correct one.
Stretchy operators as direct children of <math>
or <mtd>
Due to long-standing bug 236963 in Firefox, stretchy operators that are direct children of a <math>
or <mtd>
don't work properly in that browser. To work around this, an unnecessary <mrow>
can be used until this issue is resolved.
Related content I wrote
The New Open Source Video Game Randomizer List Is Now Live
- Video Games, Programming
Time to update your bookmarks! After a few months of work behind the scenes, the new open source version of The BIG List of Video Game Randomizer is now live for your enjoyment, with dark mode support and a brand new UI for better readability! The new URL is: https://randomizers.debigare.com/ (The…
The Future of the Video Game Randomizer List
- Video Games, Programming, Anecdotes
It's hard to believe that it's been almost 8 years since I first posted on the ROMhacking.net forums a list of video game randomizers that I found online, and that it would evolve into the massive project it has become today, with almost 900 entries currently being listed. It's always a strange…
I Designed the Perfect Gambling Game, But...
- Mathematics, Business, Game Design
Back in 2006-07-08, during the 13th Canadian Undergraduate Mathematics Conference at McGill University, I presented a gambling game I designed with the novel property of being both advantageous to players and the house, and that despite this proprety, that pretty much nobody in their right mind…
Minifying JSON Text Beyond Whitespace
- Programming, Mathematics
JSON is a common data serialization format to transmit information over the Internet. However, as I mentioned in a previous article, it's far from optimal. Nevertheless, due to business requirements, producing data in this format may be necessary. I won't go into the details as to how one could…
Current Data Serialization Formats May Be a Waste of Money
- Programming, Business
Storing data. Transmitting data. Processing data. These fundamental topics of computer science are often overlooked nowadays thanks to the historical exponential growth of processing power, storage availability and bandwidth capabilities, along with a myriad of existing solutions to tackle them. So…