This document can be viewed properly only in modern browsers with good support for CSS2 and the full HTML character set.

Math in HTML with CSS
Experiments in simple mathematical formatting
using common web technologies

The state of the art

Mathematical formatting is hard.

There hasn’t been very good support for math on the Web. Some of the solutions are:

The official, ultimate solution is MathML. As of this writing, it is just starting to be supported to some degree by two of the major browsers. MathML is not a lightweight solution though. It is easy to generate automatically, but hard to type by hand (as opposed to ). If you want just a single formula in a web page, the difficulties of using MathML might not seem worth the effort of learning it.

This is an investigation of solutions for formating math in standard HTML, enhanced by the widely-supported formatting language CSS. I have striven for

In contrast to the graphics approaches, this has the added benefits that the text

A practical principle of contemporary web design is “separate presentation from content”. It means to put the information in one place, and describe how to present it in another. This is opposed to, for example, explicitly setting the font of each word of text explicitly in the HTML code.

The most common means of describing presentation is the style language CSS. With it, you can specify the presentation of a certain kind of HTML entity in a separate document, or at the top of the page of HTML code.

For our purposes, this rendition of “separate presentation from content” is useful: Use standard characters and HTML to produce content, use CSS to beautify it.

Math symbols

It is convenient to define a CSS class selector .math. With this, any text contained in an element of class math can be specially formatted. For single-letter symbols, it’s convenient to use the selector i.mi, which will cause the symbol to be rendered in italics in older, non-CSS browsers, but leave the HTML tag <i> free to indicate generic italics.

For example, x, y, z are single math symbols in text, and

x = α y

is a math formula set off for display.

Decorated characters

Using CSS positioning, decorated characters, such as

h- x¨ v· a˜ gˆ A v

can be constructed, but won’t look good in most browsers. They are also font-dependent. I recommend that you avoid them.

Mathematics, being a very flexible language, can do without most of these fancy symbols, but quantum mechanics, without h-bar, is even more uncertain.

It’s best to stick to ISO-8859-15 characters, and the HTML 4 standard character entities. A character in bold face is representable on most browsers, too. If you really must have fancy characters such as h-bar, you might consider using Unicode. Unicode is fairly universal on computer systems since 2004 or so, but is often poorly implemented on older computer systems.

ISO-8859-15 characters

Most modern browsers support characters in the ISO-8859-15 character set. To ensure that the browser knows the character encoding of the page, place the line

<meta http-equiv="content-type" content="text/html; charset=iso-8859-15">

in the head section of the HTML document.

Besides European characters (à, å, ç, etc) there are a few math symbols: ·, ×, ÷, ¬, ±. and financial symbols: ¥, £. Note: do not rely on any of the “superscript” or “fraction” symbols from ISO-8859-1, nor the “broken vertical bar” or “currency”; they are replaced in ISO-8859-15.

The only advantage of using these is that you see the characters directly in your HTML code. All these characters are also SGML character entities: see below.

The real strength of character encodings is the ability to display text in one or more languages.

SGML character entities

A much better and ultimately more portable solution is to use SGML character entities. These are names for characters in HTML code. They are always placed between an ampersand (&) and a semicolon (;). The HTML 4 standard includes most of the Greek alphabet:

α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ ς τ υ φ χ ψ ω Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω ϑ ϒ ϖ

a fairly rich selection of math symbols:

∀ ∴ ∃ ¬ ∋ ∅ ∈ ∉ ∧ ∨ ∩ ∪ ∂ ∇ ∏ ∑ ∫ √ − ∗ × ÷ ⋅ ± ⊕ ⊗ ∝ ∞ ∼ ≅ ≈ ≠ ≡ ≤ ≥ ⊂ ⊃ ⊄ ⊆ ⊇ ∠ ⊥


← ↑ → ↓ ↔ ↵ ⇐ ⇒ ⇓ ⇔

fancier brackets:

⌈ ⌉ ⌊ ⌋ ⟨ ⟩

a few fancy script letters:

ℵ ℘ ℑ ℜ µ

and these:

◊ ♠ ♣ ♥ ♦

Most browsers will display a textual version of the entity if they can’t display a glyph for it, so that the text is still readable.

Note: Up through version 6, Microsoft Internet Explorer (MSIE) has been one of the least compliant browsers with regard to SGML Math Entities. Even entities corresponding to glyphs in character encodings that it displays correctly, it failed to display.

With MSIE 7.0 beta, things look much better. Only 5 entities are not displayed correctly (MS has been notified of these.)


In browsers that support the UTF-8 encoding, you can use the many beautiful characters in the Unicode range 8704 - 8959. You’ll need to specify the character encoding in the <head> block of your page:

<meta http-equiv="content-type" content="text/html; charset=UTF-8">

Then specify the character you want using a hexadecimal numerical character reference. For example, the Unicode numerical character reference &#x222c; is a nice double integral sign. There is also a h-bar defined in Unicode (u+0127).


Besides a browser that supports UTF-8, the user’s system has to have Unicode fonts available that contain the required glyphs.

CSS Positioning

HTML tables can be used to do much of the positioning required by math, but the code required to do this can be very cumbersome, so that the bulk of the code is about arranging the formula as a table, rather than about the formula and its parts. (Moreover, some browsers don’t even support tables).

In CSS2 came a technology that we had hoped would allow us to do very flexible positioning with simple HTML. It doesn’t always work that way. CSS positioning is very quirky, and seems to be simply missing features that one would want. However, as of this writing, most graphical browsers have fair support for it.

The main CSS1 positioning properties are


CSS2 adds

top bottom left right

It probably isn’t a good idea to mix the CSS1 properties with the position property within the same element.

The main trick with CSS2 positioning is this: absolute positioning is relative to its innermost positioned ancestor element (or the body element, if no nearer one exists). So one normally creates an element with position: relative, then within that element, other elements with position: absolute. These inner elements can be placed rather precisely, in principle.

A weakness in this scheme is that, although one can position precisely, there is no well-defined way to center positioned elements relative to one another, unless their sizes are known beforehand. So for example, one can use it to place an element above and below another element, but then there is no way to say to center the elements horizontally. One might think that, by simply not specifying the horizontal position of an absolutely-positioned elements, the positioning would somehow be governed by the CSS1 text-align property. Well, some browsers implement this, and others don’t.


The absence of standard fractions in HTML is a tragedy. Fractions are used by so many people, from auto mechanics to cooks, but there’s no nice way to write “A over B” in HTML. Even more tragic: there was a frac tag for this purpose in the HTML 3.0 standard, but it was dropped in HTML 3.2.

Fractions written with the horizontal divider are in any medium difficult to fit in-line with text, so are usually displayed separately. In the examples below however, I both display them separately and put some text around them to indicate the position of the baseline, to see if the technique used could be applied for in-line expressions.

The most portable fraction is made using a table with three rows, the middle one being the dividing line made of hyphens:


This is readable even in text browsers, so long as they support tables. But sometimes the hyphens don’t connect and you get a dotted line, and also, it’s hard to guess how many hyphens to use (they have slightly different lengths in different fonts).

HTML 4 has the frame and rules attributes, which in principle should make a line that displays in non-CSS browsers. Unfortunately, many browsers don’t support them. And Opera is broken regarding placement of rules.

(Note however: the elinks browser now supports rules quite nicely.)

One neat way to make a fraction is to use CSS box border properties with a table; unfortunately most browsers, particularly text browsers, don’t support border properties. Also, it’s another trick to align the whole fraction vertically, as the various browsers disagree widely as to the meaning of vertical-align for inline tables. The standard is fairly clear: basically, all the browsers are broken on this point.


Here we use CSS inline-table for browsers that have it, and inline for browsers that don't


This hybrid uses just div and span with line breaks, with a divider element that contains dashes for non-CSS browsers but uses border instead for CSS browsers.


While this approach is attractive in that it doesn't use tables, the absolute positioning unfortunately rules out automatic allocation of space for the fraction's contents: to leave proper vertical space, it must be tailored to fit the contents.

This is all fine for separate display of fractions, but to display them inline properly is much harder. None will work without revision.

One would think the coolest would be to use CSS positioning to make a fraction. There are several difficulties: The first is: if all the elements are absolutely positioned, they lose their natural widths. One could set the width of the containing element explicitly, or pick the widest of the numerator and denominator, and make that one non-positioned, or possibly include a string of non-breaking spaces to force the width. A related problem is the horizontal centering of the items. But all of these measures are messy, artificial, and concern more a weakness in CSS than the typesetting problem.

If the numerator and denominator are block elements (or are separated by line breaks), there are HTML ways to center them horizontally, but then putting them in-line becomes a problem. If they aren’t block elements, they can be positioned vertically with CSS, but I don’t know how to arrange for horizontal centering.

In an example below, I pick the numerator to be statically positioned to give the fraction a width. It’s picky (depends on whether the numerator or denominator is the longer) but it seems the least intrusive of the methods.

This example uses the inline-block value (now supported by most browsers) for the display property of the outermost element. The code is very clean, and centers everything nicely.

Aa0qp _________ b2

Superscripts and subscripts

HTML has always had built-in support for superscripts and subscripts, so most browsers support them to some degree.

r01 Bai

This is a place where a little CSS can make all the difference, aesthetically. The trick is the right balance of font size and vertical offset. For legibilty on a computer screen, the minimum font size is about 7 points (7 points). In printed math texts, much smaller fonts are sometimes used. On the other hand, most browsers make it easy for the user to increase the font size…maybe this is a non-issue.

To put the superscript and subscript directly over one another, there are a couple of approaches. You can try CSS positioning, but there are various technical questions. A position of absolute allows you to place an element where you like relative to the containing (relatively-positioned) element, but leaves no space on the line for the contents. A position of relative leaves space on the line where the element was. So if you know which of the sub- or superscript is longer horizontally, you can position that one relatively (to leave space for it), and position the other absolutely:

r01 Bai

Another approach is to use tables.

Integrals and Sums

A very nice integral can be assembled using the SGML entity &int; and some CSS.

There are three popular typesetting forms for integrals and sums, differing in the placement of limits relative to the integral or sum symbol. In display form, limits are centered over and under the symbol. In inline form, limits are placed as super- and subscripts to the symbol. In compact form, limits are placed to the right of the symbol, and given enough vertical spacing so that they may flow around an integrand.

Here is a compact form using sup and sub, with CSS to permit the flowing behaviour:

10 f( x ) dx

This displays well in text browsers, so long as they have a way of displaying <sup> and <sub>.

Here tables align an integral to achieve traditional typographic “compact” form, wherein the upper and lower limits flow around an integrand.

  f( x ) dx

One can use tables to align everything. A text baseline can be maintained within a line of cells. Indeed, for very complex formulas displayed out of text, this may be the best solution. However, the problem of aligning that baseline with the text baseline surrounding the table seems unsurmountable, so this technique is usually unusable for inline math. In displayed math too: once you start aligning with a table baseline, everything has to go into the table. Furthermore, to typeset a complex formula using tables can require very cumbersome HTML. Then again, very complicated formulas aligned by tables can be rendered impressively well in a text browser.


The pure CSS solution is to separately vertically align the summation symbol and limits: the main problem here is the horizontal centering of the limits on the symbol. I know of no resolution. (Is it possible with CSS to achieve horizontal centering of inline items of indeterminate width without making use of a block item?)

baseline n=0 xn baseline

A hybrid approach is perhaps best: use a table to align the limits to the symbol horizontally, then use CSS to adjust the position of the symbol relative to the baseline (which is less critical than keeping the baseline straight). The display property of the table is then set to inline so that it doesn’t break the line it’s in. (This works for browsers that handle this CSS property correctly; that includes most modern browsers.)

(Why a table again, rather than a div? because couldn’t control width of the div. Why not?)

xn baseline

Here’s an element using the CSS 2.1 inline-block value of display. This way, a positioned expression can be placed in a line, without forcing a line break in browsers that don’t know CSS. Opera and Konqueror support this; as of v. 3.0, Firefox does too. IE7 supports it buggily. Maybe the way of the future:

baseline n=0 xn baseline

Complex expressions can be formed by simply concatenating such constructions, but then the integrands won’t share the same baseline. Expressions that are made using HTML tables will normally appear on a new line because a table is a “block” element: to stop this behavior, use CSS to set its display property to inline. Unfortunately, the broswers don’t agree as to the handling of vertical placement of inline tables…

Ω  v Δu dx  =  Ω 
vxi uxi dx
 +  ∂Ω   v  du ___ dn  dS


HTML tables are ideal for placing matrix elements, but the traditional brackets around matrices are a problem.

It’s not beautiful, but a fairly good work-around is to use the vertical bar character, if you’re not concerned with the distinction between the usual enclosing square brackets and simple horizontal lines. This matrix is readable in any browser that supports tables:

|a b|
| |
|-b a|

You can use CSS box borders to make very pretty brackets, but they are displayed only in browsers that support CSS.

a b
-b a

HTML 4 tables have a frame attribute, which can be set to vsides to produce vertical bars, so in principle this could be a way to make brackets that are beautiful in CSS browsers and readable in non-CSS browsers. Many browsers don’t support this, though.

a b
-b a

Here is a hybrid, using table frames to make vertical lines, and CSS to make brackety-looking things in the better browsers.

a b
-b a

How about a norm?

a b
-b a


There is more than one way to write a square root in mathematics. One can always resort to a fractional superscript using HTML. If one really wants a traditional radical, this is also possible in HTML, using CSS, but it has limitations.

(x2 + y2 + z2)

In case the browser doesn’t have CSS, the overbar that binds the arguments of the root is lost. For this reason, it is safer to parenthesize the arguments.

But the worst problem comes from the fonts themselves. There seems to be no agreement as to how the radical sign will connect with a horizontal line. (You would think that it would simply extend to the height of the font, but no. In some fonts, it extends beyond the font height, but in others, it doesn’t reach the font height. But I think I have seen glitches of this kind in printed text, as well.)

Equation numbers

Equation numbers are pretty easy to achieve by wrapping an expression in the middle cell of a table of width 100%, and putting the equation number in the rightmost cell with text-align set to right. (To make the right-alignment function in Links, you have to use the deprecated align attribute of <td>.

a b
-b a

Standards wishlist

Browser performance

  FF/M7IE7OSfiC K A lk lx
Fraction with table, dash GUGGUGUGG
Fraction with rules PUBBGBBGB
Fraction with CSS GPGPPGBBB
Fraction with inline-table PPBBGB
Fraction hybrid PPPBBR
Fraction with inline-block PPPBBB
Superscript subscript PGPGGPBRR
Sum with inline-block PBPGBGBBB
Integral with CSS GG*PGUGB(cs)U(u)R
Integral with table GGPGGGU(c)RU(t)
Complex expression concatenated GGGB(c)B(c)B(c)U(s)B(u)B(u)
Complex expression with tables GGGGU(s)U(c)U*R(u)B(ut)
Matrix with vert. bar GGGGGGGGG
Matrix with CSS border PPPPGPBBB
Matrix with frame PUPBPBRB
Matrix norm with frame PUPPPBGB
Matrix with frame and CSS PUPPPBR*B
Equation numbers PPPPGPBPU(t)


FF Mozilla Firefox
N7 Netscape 7 (dropped)
IE7 Internet Explorer 7
M7 Mozilla 1.7
O Opera
Sf Safari
iC iCab
N4 Netscape 4.x (dropped)
K Konqueror
A Amaya
lk Elinks
lx Lynx
P Perfect!
G Good
U Ugly—aesthetic problem only
B Bad—meaning may be lost
R Readable—good as possible under circumstances
s poor SGML support
c poor CSS support
u poor super/subscript support
t poor tables support
d fail to display SGML character entities
* see note below


BrowservP notes
FF2.0L Some matrix borders gray. I don’t understand the logic… Maybe fixed in 3.0.
No support for CSS inline-block. Fixed in 3.0.
FF1.5L Matrix borders blotchy. Fixed in 1.5.04
NS7W hr in fraction is gray
IE6W hr in fraction is gray, thin solid black border of matrix table is several pix wide. Better to use 1pt rather than thin.
IE7W hr in fraction is gray.
Opera9.6 L Incorrect drawing of table rules
Math SGML chars take too much horiz. room. (6.1 vastly improved; fixed in 8.51)
Wrong positioning of table elements whose “block” attribute has been turned off in CSS. (fixed in 9.0)
elinks0.10.4L Very impressive implementation of table frames and rules. Issue with choice of frame logic (see below).
Wrong handling of Greek entities
lynx2.8rel4L Wrong handling of Greek entities
No table rules. Tables generally poor.
Amaya9.55 Version 9.55 is substantially worse than 9.51 in several respects (bad release?). Most line-drawing has ceased to work. It has also lost all SGML entities. Went from being better than the text-based browsers to worse.
Sup/subscripts — CSS positioning way out of whack. maybe interprets completely wrongly
Complex expression w/table: integral sign way too high?
Fails to center tables correctly even when they have margin: auto are in a div with text-align: center.
Ver. 9 actually got worse than previous versions in the equation numbering category.
Konqueror4.1+L SGML problems finally resolved.
Konqueror3.5+L Improved SGML, but most math symbols are still missing. (Bug was reported years ago—they blame it on Qt.)

So far, table frames and rules are supported by IE, Mozilla/Firefox/Netscape, Opera, Safari, and Elinks. Konqueror tries, but doesn’t get it right. Both Opera and Safari draw rules where they should not. (Opera started doing this recently.)

Frame logic in Mozilla, MSIE, and Elinks is different. Both MSIE and Elinks treat frame and rules as an enhancement to an existing border attribute, while Mozilla treats them as an override to border. So MSIE and Elinks show nothing if border is absent, but frame are specified. But even at that, MSIE puts rules on either side of each thing, rather than between them, and Mozilla and Elinks do. Oh, dear. And frame="lhs" puts a line at the left of each column, not just to the left of the table.

Opera doesn’t render at all lines with fractional CSS widths. This is wrong behaviour. But many of the browsers have glitches in this regard. I think that implementing anti-aliasing to represent the fractional part of a line width is the solution.

Regarding integrals with CSS, and positioning in general: it is disappointing but unsurprising that, among the major browser the one most challenged by CSS position is IE7. It simply does the wrong thing with the bottom property. This renders this property useless for cross-browser typesetting. A work-around is to always use the top property.

The control of table frames and rules, and of horizontal rule, using CSS is also muddled. The Mozilla browsers take the border properties as definitions of how to render frames and rules. Konqueror gives no (obvious) control of frame and rule presentation, and considers them to be independent of CSS borders.

Netscape seems to have dropped support for all operating systems other than Windows. Nobody really cares. So I drop support for them.

Links fails to display Unicode correctly even on a terminal that supports Unicode. For example, in a terminal that can display the h-bar Unicode character, Links displays a capital H. Curiously, Lynx will display correctly Unicode test, but if a Unicode character appears in a web page, it is also incorrectly rendered.


While most graphical browsers provide good support for most SGML entities on the screen, many fail to print them properly.

In most cases, display is better than printing. Mozilla doesn’t print all these characters correctly, at least on Linux. Lynx and links should have no problem, but they tranliterate Greek SGML characters to Latin! It’s an easy fix, and their maintainers have been contacted.

This is particularly pronounced in Linux/unix, where there has never been a unified printing interface. Firefox for Linux fails to print most SGML symbol characters, while Opera 9 is only missing a dozen or so.

There is a different printing interface for Mozilla called xprint that uses X Windows rather than PostScript to print. I couldn’t get it to work, but it is said to fix the problem.

Printing on Windows is better: Opera 7 prints SGML entities quite beautifully.

See also