Producing mathematical content (e.g., mathematical expressions, equations, matrices) for the Web has been a longstanding challenge for publishers—especially Science, Technical, and Medical (STM) houses, who make heavy use of math content in their publications. MathML is a markup language specifically designed to surmount the stumbling blocks of formatting math for the Web, and with the release of the HTML5 specification—which formalizes support for embedding MathML in HTML documents—it has been anointed a firstclass citizen in Web pages.
This chapter provides a brief introduction to MathML syntax, followed by an example of an MathMLpowered interactive equation solver, and a discussion of MathML development tools and crossbrowser compatibility.
MathML is an XML vocabulary, which provides a set of tags expressly designed for annotating mathematical content, just as HTML is fashioned for annotating textual content). Unlike HTML, however, there are actually two distinct flavors of MathML: one called presentation markup and one called content markup. Presentation markup contains a set of elements that are formattingbased and describe the visual properties of mathematical equations and expressions. In contrast, content markup describes expressions by the mathematical operations that are performed within them. As an example of the differences in these two paradigms, let's take a look at the simple mathematical expression ½.
When defining this expression in "presentational" terms, one would say, "This expression is a fraction with a numerator of one and a denominator of two." When defining in "content" terms, one would instead say, "This expression performs the operation of dividing the number one by the number two."
Moving forward in this chapter, we will focus exclusively on MathML presentational markup, for the following reasons:
Presentation markup is specifically geared to address the problem of how to render mathematical expressions, which is what is of primary concern to publishers who are trying to format this content for publication. It enables you to distinguish between the expression ½ and the expression 1 ÷ 2.
Content markup is not widely supported among major Web browsers/ereaders.
If you're interested in learning more about content markup, see the W3C MathML Content Markup spec for details.
Presentation MathML
markup defines a series of elements for tagging the building
blocks of mathematical expressions and equations, including numbers,
operators, fractions, superscripts/subscripts, grouping elements, and
matrices. Each mathematical expression is nested in a root
<math>
tag, just as all Web page content is
nested in a root <html>
tag:
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
>
Equation content goes here
</math>
In order to ensure that browsers and ereading systems recognize
this content as MathML, a namespace
declaration
(xmlns="http://www.w3.org/1998/Math/MathML"
) must be
added, which specifies that all markup in the
<math>
block is part of the MathML vocabulary
associated with the unique identifier
http://www.w3.org/1998/Math/MathML
.
Here's an overview of key presentation MathML elements that can be
used in a <math>
element, with some examples of
each:
<mn>
Used to mark up numbers. Per the MathML spec,
<mn>
content is typically rendered in
roman font (not italic or slanted) by default:
<mn>
18</mn>
<mn>
98.6</mn>
<mn>
99,999,999</mn>
<mn>
should only be used to tag
content that is composed of digits and corresponding
"punctuation"—e.g., commas and decimal points. It should not be
used to tag symbols for constants like π, or to tag
fractions.
<mi>
Used to tag identifiers in mathematical expressions. In this context, an identifier can be a constant (e.g., π or e), a variable (e.g., x or y), or a mathematical function (e.g., log or sin):
<mi>
e</mi>
<mn>
2</mn>
<mi>
Π</mi>
<mi>
r</mi>
<mo>
Used to tag operators in mathematical expressions, typically symbols that represent operations to be performed (e.g., addition, multiplication, or equals):
<mn>
2</mn>
<mo>
+</mo>
<mn>
2</mn>
<mo>
=</mo>
<mn>
4</mn>
<mi>
log</mi>
<mn>
10</mn>
<mo>
=</mo>
<mn>
1</mn>
While operators are often explicit in mathematical
expressions—for example, the + sign in 2 + 2 =
4
—they are often implicit and are not represented by a
character in the rendered equation. In the above expression
2πr
, there are actually two implicit
multiplication operators, as the equation could be written more
explicitly as 2×π×r
. Best practices in MathML
dictate that "invisible operators" should be represented as entities
tagged by <mo>
^{[3]}. To represent implicit multiplication operators, use
the entity ⁢
. Here is a
better representation of 2×π×r
in MathML
<mn>
2</mn>
<mo>
⁢
</mo>
<mi>
Π</mi>
<mo>
⁢
</mo>
<mi>
r</mi>
For implicit function operations (e.g., log
10
), use the entity
⁡
:
<mi>
log</mi>
<mo>
⁡
</mo>
<mn>
10</mn>
<mo>
=</mo>
<mn>
1</mn>
<mrow>
Used to group subexpressions in a larger mathematical expression:
<mrow><mn>
2</mn>
<mo>
⁢
</mo>
<mi>
x</mi></mrow>
<mo>
=</mo>
<mn>
6</mn>
<mfrac>
Used to tag fractions. The <mfrac>
element expects two "child" elements nested within it: the first
element is the numerator of the fraction, and the second is the
denominator. The following MathML markup:
<mfrac>
<mn>
3</mn>
<mn>
4</mn>
</mfrac>
will render as the fraction ¾.
For situations in which you have more complex expressions in
either the numerator or denominator, which encompass more than one
MathML tag, use <mrow>
elements to group
the numerator and denominator expressions. For example, the
following MathML:
<mfrac>
<mrow><mn>
2</mn><mo>
⁢
</mo><mi>
x</mi></mrow>
<mrow><mn>
3</mn><mo>
⁢
</mo><mi>
y</mi></mrow>
</mfrac>
renders as the fraction $\frac{2x}{3y}$
<msup>
Used to tag superscripted content in mathematical
expressions. Like <mfrac>
, the
<msup>
element expects two child elements
nested within it. The first element is the "base" expression, and
the second element is the superscripted expression. So the
expression x^{2} is
represented in MathML as:
<msup>
<mi>
x</mi>
<mn>
2</mn>
</msup>
Although it may be counterintuitive, the base expression
must be included in the
<msup>
element. The following markup is
not vaild MathML:
<mi>
x</mi><msup><mn>
2</mn></msup>
As with <mfrac>
, if either the base
or the superscript is a complex expression of more than one MathML
tag, wrap it in an <mrow>
element. The
following markup represents
2^{x+1}:
<msup>
<mn>
2</mn>
<mrow><mi>
x</mi>
<mo>
+</mo>
<mn>
1<mn></mrow>
</msup>
<msub>
Used to tag subscripted content in mathematical expressions.
The syntax follows the same pattern as
<msup>
. <msub>
must have two child elements: a base expression followed by the
subscripted expression:
<msub>
<mi>
y</mi>
<mn>
1</mn>
</msub>
The above markup renders as y_{1}
<msqrt>
Used to tag content that should fall within a square root symbol. The following markup will render as $\sqrt{{x}^{2}}$
<msqrt>
<msup>
<mi>
x</mi>
<mn>
2</mn>
</msup>
</msqrt>
Now that we've covered some core fundamentals of MathML markup—numbers, variables, operators, fractions, superscripts/subscripts, and square roots—let's put this knowledge into practice and construct the quadratic formula.^{[4]} Equation 41 shows the standard rendering of the quadratic formula, as seen in most math textbooks:
Example 41 shows the quadratic formula constructed in presentation MathML, with annotations explaining each chunk of the markup:
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
>
<mrow>
<mi>
x</mi>
<mo>
=</mo>
<mfrac>
<mrow>
<mo>
</mo>
<mi>
b</mi>
<mi>
±
</mi>
<msqrt>
<mrow>
<msup>
<mi>
b</mi>
<mn>
2</mn>
</msup>
<mo>
</mo>
<mn>
4</mn>
<mo>
⁢
</mo>
<mi>
a</mi>
<mo>
⁢
</mo>
<mi>
c</mi>
</mrow>
</msqrt>
</mrow>
<mrow>
<mn>
2</mn>
<mo>
⁢
</mo>
<mi>
a</mi>
</mrow>
</mfrac>
</mrow>
</math>
Every block of MathML needs to be nested in a root


Here, we're wrapping the entire quadratic equation in a


And here's the start of our fraction, which comprises the
entire right side of the formula. The


This first 

The content 

Here's our square root. Again, because


Another 

The 

Note the two occurrences of


Finally, we're moving on to the second


Again, another 

And we're done. Phew! 
Figure 42 shows our quadratic formula rendered on a Web page in the Firefox browser for Mac.
In the previous section, we constructed the quadratic formula in MathML. But we haven't yet taken advantage of the rich capabilities that comes along with embedding MathML content in an HTML document. When you add HTML markup to a web page, you have the full power of CSS at your disposal to style your content and the scriptability of JavaScript to make the content dynamic. This is equally true of MathML, which means you can apply CSS and JavaScript to your equations in the same fashion you apply them to the rest of the HTML document.
Let's use CSS and JavaScript to take our quadratic formula to the next level, and turn it into a quadratic equation solver, where the reader can input values for the constants in the quadratic formula (a, b, and c), and behind the scenes, a script will solve for x and output the solution(s). To start, we'll first construct our solver in HTML and add CSS to style the constants in the equation for enhanced readability and comprehension. Then we'll write JavaScript to add the interactive solving functionality.
For our interactive equation solver, let's put together an HTML page with the following elements:
A brief explanation of quadratic equations, followed by a MathML representation of the standard quadratic equation (ax^{2}+bx+c=0).
A MathML representation of the quadratic formula, which will be updated interactively with the values supplied by the reader.
A placeholder line following the quadratic formula (x = {?}), where the quadratic formula solutions will be displayed
An "equation solver" box, where the reader can input her own values for a, b, and c in order to obtain the solution.
Here is the HTML for piece #1, which includes a standard HTML
<head>
, an introductory paragraph about
quadratics, and our standard quadratic equation in MathML:
<?xml version="1.0" encoding="UTF8" standalone="no"?>
<!DOCTYPE html>
<html
xmlns=
"http://www.w3.org/1999/xhtml"
>
<head>
<title>
Quadratic Equation Solver</title>
<! CSS <style> tag and JS <script> tags will be inserted here >
</head>
<body>
<p>
Quadratic equations can be written in the form:</p>
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
class=
"size_3 resizable"
id=
"quadratic_equation"
>
<mrow>
<mi
class=
"constant a"
>
a</mi>
<msup>
<mi>
x</mi>
<mn>
2</mn>
</msup>
<mo>
+</mo>
<mi
class=
"constant b"
>
b</mi>
<mi>
x</mi>
<mo>
+</mo>
<mi
class=
"constant c"
>
c</mi>
<mo>
=</mo>
<mn>
0</mn>
</mrow>
</math>
All the MathML elements in the quadratic equation above are
covered in “A FifteenMinute Introduction to MathML”. However, there are a
few key attribute additions to some of these elements. First, an
id
attribute with the value
quadratic_equation
has been added to the root
<math>
element. Just as on HTML elements, this
serves as a unique identifier that we can use to reference this equation
from within CSS or JavaScript. Similarly, different
class
attributes have been added to specific
<mi>
elements. All constants are identified
with a class of constant
, as well as an additional
value of a
, b
, or
c
to indicate the specific constant identifier. These
class
values provide more granular categorization of
these constants and operates, in order to facilitate styling and
scripting of these elements.
Note also that we have removed the
⁢
operators to indicate implicit
multiplication operations. While it certainly is good in theory to
include them, in practice, they cause rendering problems in both
Google Chrome and the iBooks reader, and it's simpler and more
expedient to remove them than to attempt to employ fancy CSS styling
and/or custom entity declarations to work around the problems. I'd
definitely recommend leaving out
⁢
if you're developing for
iBooks.
Now, here's piece #2: the quadratic formula:
<p>
Here'
s the formula for solving quadratic equations</p>
<div
class=
"formula"
>
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
class=
"size_3 resizable"
id=
"quadratic_formula"
>
<mrow>
<mi>
x</mi>
<mo>
=</mo>
<mfrac>
<mrow>
<mo>
</mo>
<mi
class=
"constant b"
>
b</mi>
<mi>
±
</mi>
<msqrt>
<mrow>
<msup>
<mi
class=
"constant b"
>
b</mi>
<mn>
2</mn>
</msup>
<mo>
</mo>
<mn>
4</mn>
<mo
class=
"dot_operator"
>
⋅
</mo>
<mi
class=
"constant a"
>
a</mi>
<mo
class=
"dot_operator"
>
⋅
</mo>
<mi
class=
"constant c"
>
c</mi>
</mrow>
</msqrt>
</mrow>
<mrow>
<mn>
2</mn>
<mo
class=
"dot_operator"
>
⋅
</mo>
<mi
class=
"constant a"
>
a</mi>
</mrow>
</mfrac>
</mrow>
</math>
</div>
The above MathML is largely identical to that shown in Example 41, with just a couple noteworthy changes. Again,
we've added an id
on the root
<math>
element, to identify it as the quadratic
formula. We've also added class
values on the
<mi>
s representing the constants for
a, b, and
c; these class
es are consistent
with those used in the MathML for the quadratic equation. The other main
modification is that we are using explicit dot
operator characters (⋅
) to
indicate multiplication. (The reason for this is that we'll be scripting
the quadratic formula to make the constants dynamically updateable, and
we'll need a visible indicator to separate values when, say,
4ac gets changed to 4 ⋅ 3 ⋅
2).
Moving onto the third chunk of HTML, we'll add our placeholder for the solution:
<div>
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
class=
"size_3 resizable"
id=
"formula_solution"
>
<mrow>
<mi>
x</mi><mo>
=</mo>
<! Wanted to use "mfenced" here, but it rendered badly in some browsers >
<mtext>
{</mtext><mn
id=
"equation_solution"
>
?</mn><mtext>
}</mtext>
</mrow>
</math>
</div>
This will render in the browser as x = { ? }
.
As indicated in the comment before the <mo>
line, the ideal markup to use to specify braces around the solution
value would be the <mfenced>
element, which is specifically designed to block off
mathematical expressions with braces, parentheses, or brackets; however,
unfortunately, rendering support for <mfenced>
is not currently robust enough in Mobile Safari or the iBooks reader to
meet our needs here (the curly braces don't render properly), so using
<mtext>
afforded wider compatibility. Note the
id
value of equation_solution
on
the <mn>
element currently holding the
?
; this is a placeholder where our equation solver
will drop in the solution to the quadratic formula after the user adds
her values for a, b, and
c.
We've now completed all the MathML markup. Now all that's left are the interface elements for the user to interact with the equation solver. Here, in piece #4, we add two buttons that the user can use to resize the MathML equations:
<div
class=
"buttons"
>
<p>
<span
class=
"button"
id=
"minus_button"
>
−
</span>
<span
class=
"button"
id=
"plus_button"
>
+
</span>
<
 Click these buttons to resize the quadratic equation and formula</p>
</div>
Finally, for piece #5, we add a <form>
with fields where the user can input the constant values of her
choice:
<form
id=
"formula_values"
>
<h3>
Quadratic Equation Solver</h3>
<p>
Enter integer values for<span
class=
"a"
>
a</span>
,<span
class=
"b"
>
b</span>
, and<span
class=
"c"
>
c</span>
to solve a quadratic equation:</p>
<p><label
for=
"input_a"
class=
"a"
><em>
a:</em></label>
<input
id=
"input_a"
size=
"3"
/>
<span
id=
"up_a"
class=
"up_button"
>
▲
</span>
<span
id=
"down_a"
class=
"down_button"
>
▼
</span>
<label
for=
"input_b"
class=
"b"
><em>
b:</em></label>
<input
id=
"input_b"
size=
"3"
/>
<span
id=
"up_b"
class=
"up_button"
>
▲
</span>
<span
id=
"down_b"
class=
"down_button"
>
▼
</span>
<label
for=
"input_c"
class=
"c"
><em>
c:</em></label>
<input
id=
"input_c"
size=
"3"
/>
<span
id=
"up_c"
class=
"up_button"
>
▲
</span>
<span
id=
"down_c"
class=
"down_button"
>
▼
</span></p>
<p><input
id=
"solve_button"
type=
"submit"
value=
"Solve equation"
/></p>
<p
id=
"error_log"
>
Enter integer for<em>
a</em><br/>
Enter integer for<em>
b</em><br/>
Enter integer for<em>
c</em><br/>
</p>
</form>
The HTML above contains three <input>
fields where the user can enter her a,
b, and c values. Each
<input>
has an id
and a
corresponding <label>
that indicates which
constant value it takes. Next to each input, there are
<span>
s with class
values of
up_button
and down_button
, which
will be styled with CSS to create uparrow and downarrow buttons next
to each field, which the user can use to increment or decrement constant
values instead of typing in the fields directly.
The uparrow and downarrow buttons will actually be a UI necessity for functionality in the iBooks reader, which does not provide access to the iOS keyboard for inputting data into form fields when you are reading standard EPUB books. (Keyboard access is, however, available when accessing widgets within iBooks Author–generated content.)
Now that the HTML and MathML is in place, let's style all this
content with CSS. You can apply styling to MathML using selectors and
properties in exactly the same fashion as is done for HTML. For example,
the following CSS will render all <mn>
elements
in your document in the color green, with a dashed border surrounding
them:
mn
{
color
:
green
;
border
:
dashed
;
}
There are three main styling tasks we'll be accomplishing with our CSS:
Styling to support equation resizing via the buttons we created in HTML piece #4
Styling for the mathematical elements in the quadratic equation and quadratic formula
Styling for the userinterface elements in the "equation solver" box
To start off, here is the CSS to support setting the MathML equations at different sizes:
math
.size_1
{
fontsize
:
1em
}
math
.size_2
{
fontsize
:
2em
}
math
.size_3
{
fontsize
:
3em
}
math
.size_4
{
fontsize
:
4em
}
math
.size_5
{
fontsize
:
5em
}
Each of these CSS selectors is in the format
math.size_
N
, where
N
is a number from 1 to 5. These selectors
will apply a font size of 1em
to
<math>
elements with a class
of size_1
, a font size of 2em
to
<math>
elements with a class
of size_2
, and so on. With this styling in place, all
we'll need to do with JavaScript is change the class
on the <math>
elements to a different
size_
N
value, and the
equation size will automatically adjust accordingly.
Next, we have a set of CSS to style the math elements within each equation. We'll customize the rendering of the constants, and the dot operator:
math
.constant
{
fontweight
:
bold
}
.a
{
color
:
red
}
.b
{
color
:
green
}
.c
{
color
:
blue
}
.dot_operator
{
color
:
gray
}
The first four lines above contain the styling for the constants.
All a, b, and
c constants have a class value containing
constant
, so they will all receive a bold font
weight. In addition to the bold styling, instances of each constant
letter are rendered in a different color: red for
a, green for b, and blue for
c.
For the quadratic formula, where we use the dot operator, we set a color of gray to soften the rendering a bit and make the dots less obtrusive.
Finally, we need to add some styling for the elements in the "equation solver" box:
#input_a
:focus
{
backgroundcolor
:
#F2B1B7
}
#input_b
:focus
{
backgroundcolor
:
#96CF91
}
#input_c
:focus
{
backgroundcolor
:
#B59EF7
}
span
.button
{
border

radius
:
3px
;
border
:
1px
solid
black
;
padding
:
1px
1px
1px
1px
;
fontsize
:
2em
;
backgroundcolor
:
#C0C0C0
;
cursor
:
pointer
;
}
span
.up_button
{
position
:
relative
;
fontsize
:
.5em
;
top
:
.5em
;
cursor
:
pointer
;
}
span
.down_button
{
position
:
relative
;
fontsize
:
.5em
;
top
:
.5em
;
left
:
1.05em
;
cursor
:
pointer
;
}
form
#formula_values
{
padding
:
10px
;
border
:
1px
solid
black
;
width
:
400px
;
}
#error_log
{
color
:
red
;
}
The first three lines set a "focus" background color for the input fields in the equation solver box, which will be displayed when the field is active for text entry.
The span.up_button
and
span.down_button
blocks serve to position the up and
down arrows for incrementing/decrementing the constant values in the
input fields; their locations are set relative to their existing
position in the document flow, which is directly after the corresponding
<input>
element. A font size of
.5em
is set for the arrow characters, and again the
cursor is set to be a pointer.
The HTML5 <input type="number">
element
actually provides the exact functionality we're creating above,
creating a field that accepts numerical input with up and down arrow
buttons to the right for incrementing and decrementing. However, at
the time of writing, not every modern Web browser supports
<input type="number">
(e.g., no support in
Firefox at this time), so I chose the above method for broader
comptability.
Next, in form#formula_values
, we set the
<form>
element representing the "equation
solver" box to be 400 pixels wide, give it a 1pixel black border, and
set 10 pixels of padding between the border and the content
within.
Finally, for the #error_log
section, where
we'll insert any error messages resulting from user input, we set a
color of red to make the text stand out a bit more.
With all the HTML and CSS now in place, let's see how our page renders. Figure 44 shows the equation solver page as displayed in Safari for Mac.
With both HTML and CSS in place, all that's left to do is make the solver interactive, which entails three steps:
Activate all the UI buttons and input fields, so that we can capture the user's values for a, b, and c.
Update the corresponding constants in the MathML equations up top when the user supplies new values for a, b, and c.
Actually solve the quadratic equation for the constants
supplied by the user, and print the solution in the x =
{?}
slot below the equations
We'll wrap all our code in a MathMLApp()
function, which will be triggered when the window has loaded:
window
.
addEventListener
(
'load'
,
eventWindowLoaded
,
false
);
function
eventWindowLoaded
()
{
MathMLApp
();
}
function
MathMLApp
(){
// Our code for steps 1–3 will go here
}
For step 1, we will add event handlers and corresponding functions
that will be triggered to run when buttons or clicked, or the input
fields are deselected. We'll use the jQuery bind()
function, which greatly simplifies the code required to
accomplish this task. To bind a function to a specific DOM event, the
code is as follows:
$
(
"SELECTOR"
).
bind
(
'EVENT'
,
FUNCTIONTORUN
);
Where SELECTOR
specifies a CSS selector
that indicates the page elements to which the function will be bound,
EVENT
specifies the user action on the
elements that will trigger the function, and
FUNCTIONTORUN
specifies the function to run
when the trigger occurs.
You can also embed the function code directly within
bind()
, in which case the syntax looks like
this:
$
(
"SELECTOR"
).
bind
(
'EVENT'
,
function
(
e
)
{
// Put your function code here
});
Here's all the code for the event handling of the UI elements in the equation solver:
$
(
"#plus_button"
).
bind
(
'click'
,
function
(
e
)
{
// Get all elements of @class "resizable"
$
(
".resizable"
).
each
(
function
()
{
var
resizableClass
=
$
(
this
).
attr
(
"class"
);
// Strip out "resizable" from class to get the size value
var
sizeValue
=
resizableClass
.
replace
(
/ resizable/
,
''
);
// Extract size value
formulaSizeClassPrefix
=
sizeValue
.
split
(
'_'
)[
0
];
existingFormulaSize
=
Number
(
sizeValue
.
split
(
'_'
)[
1
]);
newFormulaSize
=
existingFormulaSize
+
1
;
if
(
newFormulaSize
>
5
)
{
alert
(
"Formulas already displayed at maximum size"
);
// Exit jQuery each() loop
return
false
;
}
else
{
newFormulaSizeClass
=
formulaSizeClassPrefix
+
'_'
+
String
(
newFormulaSize
);
// Reconstruct new @class attribute and update element
newClassAttribute
=
newFormulaSizeClass
+
" resizable"
;
$
(
this
).
attr
(
'class'
,
newClassAttribute
);
}
});
});
$
(
"#minus_button"
).
bind
(
'click'
,
function
(
e
)
{
// Get all elements of @class "resizable"
$
(
".resizable"
).
each
(
function
()
{
var
resizableClass
=
$
(
this
).
attr
(
"class"
);
// Strip out "resizable" from class to get the size value
var
sizeValue
=
resizableClass
.
replace
(
/ resizable/
,
''
);
// Extract size value
formulaSizeClassPrefix
=
sizeValue
.
split
(
'_'
)[
0
];
existingFormulaSize
=
Number
(
sizeValue
.
split
(
'_'
)[
1
]);
newFormulaSize
=
existingFormulaSize

1
;
if
(
newFormulaSize
<
1
)
{
alert
(
"Formulas already displayed at minimum size"
);
// Exit jQuery each() loop
return
false
;
}
else
{
newFormulaSizeClass
=
formulaSizeClassPrefix
+
'_'
+
String
(
newFormulaSize
);
// Reconstruct new @class attribute and update element
newClassAttribute
=
newFormulaSizeClass
+
" resizable"
;
$
(
this
).
attr
(
'class'
,
newClassAttribute
);
}
});
});
$
(
".up_button"
).
bind
(
'click'
,
function
(
e
)
{
var
upButtonPressed
=
e
.
target
;
var
upButtonId
=
upButtonPressed
.
getAttribute
(
"id"
);
var
correspondingInputId
=
upButtonId
.
replace
(
/up/
,
'input'
);
var
correspondingInputElement
=
document
.
getElementById
(
correspondingInputId
);
var
currentInputValue
=
$
(
correspondingInputElement
).
val
();
if
(
currentInputValue
!=
""
)
{
var
newInputValue
=
parseInt
(
currentInputValue
)
+
1
;
$
(
correspondingInputElement
).
val
(
newInputValue
);
updateFormula
();
}
else
{
$
(
correspondingInputElement
).
val
(
"1"
);
updateFormula
();
}
});
$
(
".down_button"
).
bind
(
'click'
,
function
(
e
)
{
var
downButtonPressed
=
e
.
target
;
var
downButtonId
=
downButtonPressed
.
getAttribute
(
"id"
);
var
correspondingInputId
=
downButtonId
.
replace
(
/down/
,
'input'
);
var
correspondingInputElement
=
document
.
getElementById
(
correspondingInputId
);
var
currentInputValue
=
$
(
correspondingInputElement
).
val
();
if
(
currentInputValue
!=
""
)
{
var
newInputValue
=
parseInt
(
currentInputValue
)

1
;
$
(
correspondingInputElement
).
val
(
newInputValue
);
updateFormula
();
}
else
{
$
(
correspondingInputElement
).
val
(
"1"
);
updateFormula
();
}
});
$
(
"#input_a"
).
bind
(
'blur'
,
updateFormula
);
$
(
"#input_b"
).
bind
(
'blur'
,
updateFormula
);
$
(
"#input_c"
).
bind
(
'blur'
,
updateFormula
);
$
(
"#solve_button"
).
bind
(
'click'
,
function
(
e
)
{
// Prevent default formsubmission action and try to solve the equation
e
.
preventDefault
();
updateFormula
(
e
);
});
In the first two blocks, we bind functions to the elements with
the id
s plus_button
and
minus_button
, which are used to resize the MathML
equations on the page. When these buttons are clicked^{[6]}, we cycle through each element with a
class
value containing resizable
(all the <math>
elements), and get the size
information contained in the class value (in the format
size_
N
, where
N
is a number from 1 to 5). For the plus
button we update the class
by incrementing the size
number by 1, and for the minus button, we update the
class
by decrementing it by 1.
In the next two blocks, we bind functions to the up and down
arrows next to each input field. When the user clicks these buttons, we
locate the input field with the id
(of format
input_
a
) that corresponds
to the button id
(of format
up_
a
or
down_
a
), where
a
is the constant a
,
b
, or c
. If the input field
contains a value, for the up buttons, we increment it to the next
highest integer, and for the down buttons, we decrement it to the next
lowest integer. Then we call the updateFormula()
function to update the corresponding constant values in the quadratic
equation and quadratic formula.
In the third block, we do event handling for the three
<input>
fields, with id
s
input_a
, input_b
, and
input_c
. In all the previous
bind()
calls, we bound functions to the
click
event, which meant that the function code was
triggered when the user performed a "click" action (either a click with
the mouse, or a tap on a touchscreen device). In the case of the
<input>
fields, we're instead binding to the
blur
event, which is triggered when the user
"deselects" a form field (either by tabbing away from it on the
keyboard, or by clicking/tapping on another element). This allows us to
track when a user exits the form field, to check if she has entered new
data. We bind the updateFormula()
function to the
blur
event, so that the MathML equations will be
updated every time the user leaves a field.
In the last block, we also bind a click
event
the "Solve equation" button, which triggers the
updateFormula()
function. Note that we also include
the line e.preventDefault()
, which suppresses the
default formsubmission handling for our <form>
in favor of our custom JavaScript handling.
Now that we've got our event handling in place for all the buttons
and fields in the equation solver, we need to add the
updateFormula()
function, which will handle the task
of updating the values in the quadratic equation and quadratic formula
with the user's input, as well as call a function for solving the
quadratic equation. Here's the annotated
updateFormula()
code:
function
updateFormula
(
e
)
{
// Start out with no error text
var
errorText
=
""
;
var
aValue
=
$
(
"#input_a"
).
val
();
var
bValue
=
$
(
"#input_b"
).
val
();
var
cValue
=
$
(
"#input_c"
).
val
();
// Regex pattern for acceptable a values, which must be integers > 0
var
aPattern
=
/^?[19][09]*$/
;
// Regex pattern for acceptable b/c values, which must be integers >= 0
var
bcPattern
=
/^(0(?[19][09]*))$/
;
if
(
aValue
==
""
)
{
errorText
+=
"Enter integer for <em>a</em><br/>"
;
// Reset aValue to default of "a"
aValue
=
"a"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
else
if
(
!
(
aValue
.
match
(
aPattern
)))
{
errorText
+=
"Invalid value for <em>a</em>: "
+
aValue
+
"<br/>"
;
// Reset aValue to default of "a"
aValue
=
"a"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
if
(
bValue
==
""
)
{
errorText
+=
"Enter integer for <em>b</em><br/>"
;
// Reset bValue to default of "b"
bValue
=
"b"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
else
if
(
!
(
bValue
.
match
(
bcPattern
)))
{
errorText
+=
"Invalid value for <em>b</em>: "
+
bValue
+
"<br/>"
;
// Reset bValue to default of "b"
bValue
=
"b"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
if
(
cValue
==
""
)
{
errorText
+=
"Enter integer for <em>c</em><br/>"
;
// Reset cValue to default of "c"
cValue
=
"c"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
else
if
(
!
(
cValue
.
match
(
bcPattern
)))
{
errorText
+=
"Invalid value for <em>c</em>: "
+
cValue
+
"<br/>"
;
// Reset cValue to default of "c"
cValue
=
"c"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
$
(
"math .a"
).
each
(
function
()
{
$
(
this
).
text
(
aValue
);
});
$
(
"math .b"
).
each
(
function
()
{
$
(
this
).
text
(
bValue
);
});
$
(
"math .c"
).
each
(
function
()
{
$
(
this
).
text
(
cValue
);
});
$
(
"#error_log"
).
html
(
errorText
);
// If error text is now empty, it means valid numbers have been entered
// for a, b, and c.
// Go ahead and solve the quadratic equation
if
(
errorText
==
""
)
{
solve_quadratic_equation
(
aValue
,
bValue
,
cValue
);
}
}
In this line, and the two following, we store the values
currently in the input fields for a,
b, and c in the variables


We need to do data validation on the data entered in the field for the a constant, which must be a nonzero integer (if a were equal to zero, the equation would cease to be quadratic, because the x^{2} term would disappear). Here, we define a regular expression that specifies this condition: our input can be only be a series of one or more digits that doesn't start with 0, which may be preceded by an optional minus sign. 

Here, we define a regular expression for the data validation requirements for the b and c constants. The rules are exactly the same as for a, except a value of 0 is also acceptable. 

In this 

This 

Again, same data validation for c as for a and b. 

Now that we've completed data validation, in the next three
blocks, we cycle through all the elements in our MathML equations
that correspond to a, b,
and c (the jQuery code Remember, in the previous datavalidation steps, if the
usersupplied values for a,
b, or c failed validation,
we reverted 

Here, we update our error log element with all the messages
stored in the 

In this final 
The last piece of code needed is the
solve_quadratic_equation()
function, which
follows:
function
solve_quadratic_equation
(
aValue
,
bValue
,
cValue
)
{
var
discriminant
=
(
bValue
*
bValue
)

4
*
aValue
*
cValue
;
var
equationSolution
=
""
;
if
(
discriminant
<
0
)
{
// No solution to equation; display null set
$
(
"#equation_solution"
).
text
(
"No Solution"
);
}
else
if
(
discriminant
==
0
)
{
equationSolution
=

bValue
/
(
2
*
aValue
);
$
(
"#equation_solution"
).
text
(
equationSolution
);
}
else
{
var
solution1
=
(

bValue

Math
.
sqrt
(
discriminant
))
/
(
2
*
aValue
);
var
solution2
=
(

bValue
+
Math
.
sqrt
(
discriminant
))
/
(
2
*
aValue
);
equationSolution
=
String
(
solution1
)
+
", "
+
String
(
solution2
);
$
(
"#equation_solution"
).
text
(
equationSolution
);
}
}
Our first step in solving the quadratic equation is to calculate the discriminant of our quadratic equation (equal to b^{2} − 4ac), which tells us how many solutions the equation has. If the discriminant is less than 0, the equation has no solution; if it's equal to 0, there is one solution; and if it's greater than 0, there are two solutions. In the case where there are no solutions, we replace the ? on the solution line below the quadratic formula with the text "No Solution". If there is one solution, we print that value in the solution line. If there are two solutions, we print them both, separated by a comma, on the solution line.
Figure 45 shows the results of a successful equationsolve in the iBooks reader. Note that the quadratic equation and formula have had their a, b, and c values updated with the input from the fields below, and that the correct solution is displayed below the quadratic formula. Very cool!
Example 42 contains the full, final HTML and CSS for the equation solver, and Example 43 contains the full JavaScript. You can also download the code from the GitHub repository for HTML5 for Publishers. And don't forget to try out the example for yourself!
<?xml version="1.0" encoding="UTF8" standalone="no"?>
<!DOCTYPE html>
<html
xmlns=
"http://www.w3.org/1999/xhtml"
>
<head>
<title>
Quadratic Equation Solver</title>
<script
src=
"mathml.js"
></script>
<script
src=
"jquery1.6.2.min.js"
></script>
<style
media=
"screen"
type=
"text/css"
>
math
.size_1
{
fontsize
:
1em
}
math
.size_2
{
fontsize
:
2em
}
math
.size_3
{
fontsize
:
3em
}
math
.size_4
{
fontsize
:
4em
}
math
.size_5
{
fontsize
:
5em
}
math
.constant
{
fontweight
:
bold
}
.a
{
color
:
red
}
.b
{
color
:
green
}
.c
{
color
:
blue
}
.dot_operator
{
color
:
gray
}
#input_a
:focus
{
backgroundcolor
:
#F2B1B7
}
#input_b
:focus
{
backgroundcolor
:
#96CF91
}
#input_c
:focus
{
backgroundcolor
:
#B59EF7
}
span
.button
{
border

radius
:
3px
;
border
:
1px
solid
black
;
padding
:
1px
1px
1px
1px
;
fontsize
:
2em
;
backgroundcolor
:
#C0C0C0
;
cursor
:
pointer
;
}
span
.up_button
{
position
:
relative
;
fontsize
:
.5em
;
top
:
.5em
;
cursor
:
pointer
;
}
span
.down_button
{
position
:
relative
;
fontsize
:
.5em
;
top
:
.5em
;
left
:
1.05em
;
cursor
:
pointer
;
}
form
#formula_values
{
padding
:
10px
;
border
:
1px
solid
black
;
width
:
400px
;
}
#error_log
{
color
:
red
;
}
</style>
</head>
<body>
<p>
Quadratic equations can be written in the form:</p>
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
class=
"size_3 resizable"
id=
"quadratic_equation"
>
<mrow>
<mi
class=
"constant a"
>
a</mi>
<msup>
<mi>
x</mi>
<mn>
2</mn>
</msup>
<mo>
+</mo>
<mi
class=
"constant b"
>
b</mi>
<mi>
x</mi>
<mo>
+</mo>
<mi
class=
"constant c"
>
c</mi>
<mo>
=</mo>
<mn>
0</mn>
</mrow>
</math>
<p>
Here'
s the formula for solving quadratic equations</p>
<div
class=
"formula"
>
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
class=
"size_3 resizable"
id=
"quadratic_formula"
>
<mrow>
<mi>
x</mi>
<mo>
=</mo>
<mfrac>
<mrow>
<mo>
</mo>
<mi
class=
"constant b"
>
b</mi>
<mi>
±
</mi>
<msqrt>
<mrow>
<msup>
<mi
class=
"constant b"
>
b</mi>
<mn>
2</mn>
</msup>
<mo>
</mo>
<mn>
4</mn>
<mo
class=
"dot_operator"
>
⋅
</mo>
<mi
class=
"constant a"
>
a</mi>
<mo
class=
"dot_operator"
>
⋅
</mo>
<mi
class=
"constant c"
>
c</mi>
</mrow>
</msqrt>
</mrow>
<mrow>
<mn>
2</mn>
<mo
class=
"dot_operator"
>
⋅
</mo>
<mi
class=
"constant a"
>
a</mi>
</mrow>
</mfrac>
</mrow>
</math>
</div>
<div>
<math
xmlns=
"http://www.w3.org/1998/Math/MathML"
class=
"size_3 resizable"
id=
"formula_solution"
>
<mrow>
<mi>
x</mi><mo>
=</mo>
<! Wanted to use "mfenced" here, but it rendered badly in some browsers >
<mtext>
{</mtext><mn
id=
"equation_solution"
>
?</mn><mtext>
}</mtext>
</mrow>
</math>
</div>
<div
class=
"buttons"
>
<p>
<span
class=
"button"
id=
"minus_button"
>
−
</span>
<span
class=
"button"
id=
"plus_button"
>
+
</span>
<
 Click these buttons to resize the quadratic equation and formula</p>
</div>
<form
id=
"formula_values"
>
<h3>
Quadratic Equation Solver</h3>
<p>
Enter integer values for<span
class=
"a"
>
a</span>
,<span
class=
"b"
>
b</span>
, and<span
class=
"c"
>
c</span>
to solve a quadratic equation:</p>
<p><label
for=
"input_a"
class=
"a"
><em>
a:</em></label>
<input
id=
"input_a"
size=
"3"
/>
<span
id=
"up_a"
class=
"up_button"
>
▲
</span>
<span
id=
"down_a"
class=
"down_button"
>
▼
</span>
<label
for=
"input_b"
class=
"b"
><em>
b:</em></label>
<input
id=
"input_b"
size=
"3"
/>
<span
id=
"up_b"
class=
"up_button"
>
▲
</span>
<span
id=
"down_b"
class=
"down_button"
>
▼
</span>
<label
for=
"input_c"
class=
"c"
><em>
c:</em></label>
<input
id=
"input_c"
size=
"3"
/>
<span
id=
"up_c"
class=
"up_button"
>
▲
</span>
<span
id=
"down_c"
class=
"down_button"
>
▼
</span></p>
<p><input
id=
"solve_button"
type=
"submit"
value=
"Solve equation"
/></p>
<p
id=
"error_log"
>
Enter integer for<em>
a</em><br/>
Enter integer for<em>
b</em><br/>
Enter integer for<em>
c</em><br/>
</p>
</form>
</body>
</html>
window
.
addEventListener
(
'load'
,
eventWindowLoaded
,
false
);
function
eventWindowLoaded
()
{
MathMLApp
();
}
function
MathMLApp
(){
$
(
"#plus_button"
).
bind
(
'click'
,
function
(
e
)
{
// Get all elements of @class "resizable"
$
(
".resizable"
).
each
(
function
()
{
var
resizableClass
=
$
(
this
).
attr
(
"class"
);
// Strip out "resizable" from class to get the size value
var
sizeValue
=
resizableClass
.
replace
(
/ resizable/
,
''
);
// Extract size value
formulaSizeClassPrefix
=
sizeValue
.
split
(
'_'
)[
0
];
existingFormulaSize
=
Number
(
sizeValue
.
split
(
'_'
)[
1
]);
newFormulaSize
=
existingFormulaSize
+
1
;
if
(
newFormulaSize
>
5
)
{
alert
(
"Formulas already displayed at maximum size"
);
// Exit jQuery each() loop
return
false
;
}
else
{
newFormulaSizeClass
=
formulaSizeClassPrefix
+
'_'
+
String
(
newFormulaSize
);
// Reconstruct new @class attribute and update element
newClassAttribute
=
newFormulaSizeClass
+
" resizable"
;
$
(
this
).
attr
(
'class'
,
newClassAttribute
);
}
});
});
$
(
"#minus_button"
).
bind
(
'click'
,
function
(
e
)
{
// Get all elements of @class "resizable"
$
(
".resizable"
).
each
(
function
()
{
var
resizableClass
=
$
(
this
).
attr
(
"class"
);
// Strip out "resizable" from class to get the size value
var
sizeValue
=
resizableClass
.
replace
(
/ resizable/
,
''
);
// Extract size value
formulaSizeClassPrefix
=
sizeValue
.
split
(
'_'
)[
0
];
existingFormulaSize
=
Number
(
sizeValue
.
split
(
'_'
)[
1
]);
newFormulaSize
=
existingFormulaSize

1
;
if
(
newFormulaSize
<
1
)
{
alert
(
"Formulas already displayed at minimum size"
);
// Exit jQuery each() loop
return
false
;
}
else
{
newFormulaSizeClass
=
formulaSizeClassPrefix
+
'_'
+
String
(
newFormulaSize
);
// Reconstruct new @class attribute and update element
newClassAttribute
=
newFormulaSizeClass
+
" resizable"
;
$
(
this
).
attr
(
'class'
,
newClassAttribute
);
}
});
});
$
(
".up_button"
).
bind
(
'click'
,
function
(
e
)
{
var
upButtonPressed
=
e
.
target
;
var
upButtonId
=
upButtonPressed
.
getAttribute
(
"id"
);
var
correspondingInputId
=
upButtonId
.
replace
(
/up/
,
'input'
);
var
correspondingInputElement
=
document
.
getElementById
(
correspondingInputId
);
var
currentInputValue
=
$
(
correspondingInputElement
).
val
();
if
(
currentInputValue
!=
""
)
{
var
newInputValue
=
parseInt
(
currentInputValue
)
+
1
;
$
(
correspondingInputElement
).
val
(
newInputValue
);
updateFormula
();
}
else
{
$
(
correspondingInputElement
).
val
(
"1"
);
updateFormula
();
}
});
$
(
".down_button"
).
bind
(
'click'
,
function
(
e
)
{
var
downButtonPressed
=
e
.
target
;
var
downButtonId
=
downButtonPressed
.
getAttribute
(
"id"
);
var
correspondingInputId
=
downButtonId
.
replace
(
/down/
,
'input'
);
var
correspondingInputElement
=
document
.
getElementById
(
correspondingInputId
);
var
currentInputValue
=
$
(
correspondingInputElement
).
val
();
if
(
currentInputValue
!=
""
)
{
var
newInputValue
=
parseInt
(
currentInputValue
)

1
;
$
(
correspondingInputElement
).
val
(
newInputValue
);
updateFormula
();
}
else
{
$
(
correspondingInputElement
).
val
(
"1"
);
updateFormula
();
}
});
$
(
"#input_a"
).
bind
(
'blur'
,
updateFormula
);
$
(
"#input_b"
).
bind
(
'blur'
,
updateFormula
);
$
(
"#input_c"
).
bind
(
'blur'
,
updateFormula
);
$
(
"#solve_button"
).
bind
(
'click'
,
function
(
e
)
{
// Prevent default formsubmission action and try to solve the equation
e
.
preventDefault
();
updateFormula
(
e
);
});
function
updateFormula
(
e
)
{
// Start out with no error text
var
errorText
=
""
;
var
aValue
=
$
(
"#input_a"
).
val
();
var
bValue
=
$
(
"#input_b"
).
val
();
var
cValue
=
$
(
"#input_c"
).
val
();
// Regex pattern for acceptable a values, which must be integers > 0
var
aPattern
=
/^?[19][09]*$/
;
// Regex pattern for acceptable b/c values, which must be integers >= 0
var
bcPattern
=
/^(0(?[19][09]*))$/
;
if
(
aValue
==
""
)
{
errorText
+=
"Enter integer for <em>a</em><br/>"
;
// Reset aValue to default of "a"
aValue
=
"a"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
else
if
(
!
(
aValue
.
match
(
aPattern
)))
{
errorText
+=
"Invalid value for <em>a</em>: "
+
aValue
+
"<br/>"
;
// Reset aValue to default of "a"
aValue
=
"a"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
if
(
bValue
==
""
)
{
errorText
+=
"Enter integer for <em>b</em><br/>"
;
// Reset bValue to default of "b"
bValue
=
"b"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
else
if
(
!
(
bValue
.
match
(
bcPattern
)))
{
errorText
+=
"Invalid value for <em>b</em>: "
+
bValue
+
"<br/>"
;
// Reset bValue to default of "b"
bValue
=
"b"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
if
(
cValue
==
""
)
{
errorText
+=
"Enter integer for <em>c</em><br/>"
;
// Reset cValue to default of "c"
cValue
=
"c"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
else
if
(
!
(
cValue
.
match
(
bcPattern
)))
{
errorText
+=
"Invalid value for <em>c</em>: "
+
cValue
+
"<br/>"
;
// Reset cValue to default of "c"
cValue
=
"c"
;
// Reset answer to "?"
$
(
"#equation_solution"
).
text
(
"?"
);
}
$
(
"math .a"
).
each
(
function
()
{
$
(
this
).
text
(
aValue
);
});
$
(
"math .b"
).
each
(
function
()
{
$
(
this
).
text
(
bValue
);
});
$
(
"math .c"
).
each
(
function
()
{
$
(
this
).
text
(
cValue
);
});
$
(
"#error_log"
).
html
(
errorText
);
// If error text is now empty, it means valid numbers have been entered
// for a, b, and c.
// Go ahead and solve the quadratic equation
if
(
errorText
==
""
)
{
solve_quadratic_equation
(
aValue
,
bValue
,
cValue
);
}
}
function
solve_quadratic_equation
(
aValue
,
bValue
,
cValue
)
{
var
discriminant
=
(
bValue
*
bValue
)

4
*
aValue
*
cValue
;
var
equationSolution
=
""
;
if
(
discriminant
<
0
)
{
// No solution to equation; display null set
$
(
"#equation_solution"
).
text
(
"No Solution"
);
}
else
if
(
discriminant
==
0
)
{
equationSolution
=

bValue
/
(
2
*
aValue
);
$
(
"#equation_solution"
).
text
(
equationSolution
);
}
else
{
var
solution1
=
(

bValue

Math
.
sqrt
(
discriminant
))
/
(
2
*
aValue
);
var
solution2
=
(

bValue
+
Math
.
sqrt
(
discriminant
))
/
(
2
*
aValue
);
equationSolution
=
String
(
solution1
)
+
", "
+
String
(
solution2
);
$
(
"#equation_solution"
).
text
(
equationSolution
);
}
}
}
There are varying levels of MathML support in modern Web browsers. The Gecko engine (used by Firefox) fully supports presentation MathML. The WebKit engine (used by Safari and Google Chrome) has partial rendering support for a subset of presentation MathML elements (including all the elements used in the quadratic formula), and as part of the WebKit Open Source Project, efforts are underway to implement MathML more fully. Internet Explorer does not have native rendering support for MathML, but in IE7 and later, you can install the free MathPlayer plugin from Design Science to add this functionality.
So, given the current state of the browser ecosystem's MathML support, hoiw can HTML5 developers embed MathML content with confidence that a majority of visitors will be viewing their pages in MathMLcompatible browsers, or in browsers with MathML plugins installed? If the onus is on the client side to be using the right software, there are no guarantees. Luckily, there's a compatibility solution developers can implement: the MathJax project.
MathJax is an open source, JavaScript and CSS–based software package that is intended to provide full presentation MathML rendering support for browsers that have none, and to augment the MathML capabilities of browsers that have partial support—ensuring consistent, highquality MathML rendering across all browsers with modern JavaScript and CSS support. See the MathJax Browser Compatibility page for a full list of supported browsers.
In addition to MathML, MathJax also has rendering support for L^{A}T_{E}X, a nonXMLbased markup language for document production that has strong markup support for mathematical content. Many STM authors prefer formatting mathematical content in L^{A}T_{E}X because it is possible to write and mark up equations manually, without the burden of heavyduty XML tagging.
MathJAX doesn't require users to install any plugins or other
software for their browsers; instead, as described in the MathJax docs,
developers just add the following <script>
tag to
their HTML document's <head>
:
<script
type=
"text/javascript"
src=
"https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=
TeXAMSMML_HTMLorMML"></script>
which will load the MathJax engine from MathJax's CDN. It's also possible to download the MathJax package and host it locally on your own Web server; see the docs for more instructions on doing so.
So, what about MathML rendering support in the major ereaders? As of January 2013, per the latest data compiled by the Book Industry Study Group (BISG), both iBooks and the NOOK Color/Tablet (but not NOOK eInk devices) have MathML support. The iBooks engine is based on WebKit, so its MathML support is also partial, but good enough to render the quadratic formula (as shown in Figure 45).
It would be great if developers could embed MathJax in EPUB to add support for MathML in ereaders that cannot render MathML natively. However, not all ereaders have the JavaScript support necessary to run MathJax. On the MathJax site's "EPUB readers page", you can find a list of ereading systems that support MathML via MathJax.
If you're interested in augmenting iBooks's MathML support,^{[7]} because iBooks has JavaScript support, you can indeed embed MathJax in your EPUB and get improved rendering. For best results, you'll want to do some custom configuration specifically for iBooks. Peter Krautzberger has written up his recommended approach along with excellent stepbystep instructions in the post "How to include MathJax in an epub3 file to work with iBooks (and possibly others)", which you should definitely read before attempting to embed MathJax in an EPUB.
Some additional resources if you're interested in learning more about MathML and/or doing your own MathML development:
The definitive source of information about the MathML specification, covering both presentation and content varieties of MathML. Contains clear and detailed descriptions of MathML element semantics and syntax, with markup samples and images illustrating expected rendering.
This stylesheet provides some suggested default styling that
MathML renders can use to ensure rendering in accordance with the
MathML spec. It offers some good insights into how properties like
mathfamily
, mathcolor
, and
mathsize
should be rendered, and also may be
useful as a template if you are writing your own custom CSS for
MathML content.
Extension for Firefox that embeds a MathML editor in the browser. Good choice if you're looking for a free, Webbased MathML creation tool.
Open source JavaScript and CSS–based engine that adds/augments MathML support in Web browsers (and also some ereaders). If you're posting MathML content on the Web, most likely you will want to use MathJax. For more on MathJax and MathML compatibility, see “MathML Browser and Ereader Compatibility”.
Stepbystep guide to embedding MathJax in EPUB, primarily for use in the iBooks reader. Your mileage will vary in other ereaders (see “MathML Browser and Ereader Compatibility”)
^{[3] }For more on "invisible operators", see the MathML specification details at http://www.w3.org/TR/MathML2/chapter3.html#id.3.2.5.5.
^{[4] }The quadratic formula is a fundamental equation covered in most firstyear algebra curricula, used to solve singlevariable equations that can be written in the form ax^{2}+bx+c=0.
^{[5] }For more on best practices for grouping expressions with <mrow>, see "Proper grouping of subexpressions using <mrow>" in Section 3.3.1 of the W3C MathML specification.
^{[6] }The click
event corresponds to either a
click of the mouse, or a tap on a touchscreen device. For
conciseness, references to "click" in this section mean "click or
tap".
^{[7] }According to tests run by the W3C, the Safari 5.1 engine (based on WebKit, just like the iBooks engine) supports only 7 percent of presentation MathML's capabilities; see http://www.w3.org/Math/testsuite/results/tests.html for more details.