This page is outdated by about 3 and a half years; in particular I have used the successors to Liberation Serif, Sans, and Mono from the Google Font Directory, known respectively as Tinos, Arimo, and Cousine, rather than rolling my own Webfont stack, although I still refer to the earlier fonts in my CSS to accommodate systems with those fonts that have disabled or do not support Webfonts. (1 April 2014)

About the Fonts

If you are using a browser that supports TTF Web fonts, including Opera 10+, Safari 3.1+, or Firefox 3.5+, a browser like Internet Explorer 4+ that supports EOT Web fonts, or a browser like Chrome 0.3+ that supports SVG Web fonts, or if you have the Liberation fonts installed on your computer, you will see all text on this page in Liberation Sans, Serif, and Mono. It is surprising, but the generally forward-looking Opera browser has lagged in its support for Web Fonts behind all other current graphical Web browsers and until the release of version 10 on 1 September 2009 was instead at the level of the now-obsolete Mac-only browsers Internet Explorer for Mac and iCab 3.

Fedora Hosted hosts the free and open-source Liberation fonts, originally produced by Ascender Corporation; the CSS used to embed them came from Prince XML, although I have used updated versions of the TTF files from Fedora and altered the original CSS accordingly. I have also used ttf2svg from Apache Batik to convert to SVG format for the benefit of Chrome, ttf2eot to convert to EOT format for use by IE, and sfnt2woff to convert to WOFF for Firefox 3.6 or later; appropriate CSS files are included in the archives, and to use them, extract the files with your preferred 7z archive manager and upload all of the files to the root of your website or edit the CSS to point to wherever you have uploaded the EOT and SVG files. You may want to use @import(url) to include these special CSS files inside your larger stylesheets, the SVG stylesheet in the general layout and the EOT sheet in the IE-only layout, which should be hidden behind conditional comments (@import(url) only works in IE8+; for earlier versions use @import url with no media declaration).

If you do not use a browser capable of downloading and displaying Web fonts, like Opera before version 10, iCab before version 4, or Internet Explorer for Mac, and you do not have the Liberation fonts installed on your computer, you will see Times, Times New Roman, or your default serif; Helvetica, Arial, or your default sans-serif; and Consolas, Lucida Console, Courier New, or your default monospace font. These font stacks are arranged in the order in which your browser will search for the font on your computer; it should be noted that the Liberation typefaces are metric-compatible with Microsoft's Times New Roman, Arial, and Courier New, respectively, so the Liberation fonts are interchangeable with the old default Microsoft fonts without distorting any design elements.

The Wonderful World of Text Effects

Ready for Use

These effects have broad enough support to use right now, either because the latest stable versions of browsers other than IE, along with sufficiently recent versions of IE, allow them, or because their lack does not detract from the user experience.

Text Shadows

Text shadows can be achieved via the text-shadow: CSS property in Opera 9.5+, Firefox 3.5+, Safari 3+, Chrome, Konqueror 3.4+, and iCab 3.0.3+, and by the progid:DXImageTransform.Microsoft.Shadow(sProperties) filter in IE5.5+ (hasLayout must be set to true, and one way is to set the width, as I have).

If your browser supports text shadows, you should see them.

In the above paragraph, I went ahead and used an inline style, because I do not intend to use this effect often, but if you do intend to use it on a regular basis, be sure to set all shadowed elements to the same class, like "shadow", and then put all of this style information into a class declaration for .shadow in your external stylesheet, probably splitting the filter off into the IE-only sheet; unfortunately, as with many DirectX filters, this one disables font smoothing, so this example does not look good in Internet Explorer.

The first portion of the style was used merely to make the text large enough to be legible in IE after loss of font smoothing; next came text-shadow:2px 3px 2px #000000;, which means a shadow 2 pixels to the right and 3 pixels down from the text, with a 2-pixel blur and base color black (#000000). After that, width:100%; is used so that IE will consider the paragraph to have Layout and has no other effect; finally, filter:progid:DXImageTransform.Microsoft.Shadow(color=#CCC,direction=135,strength=3); applies a filter with the program ID DXImageTransform.Microsoft.Shadow, which is a DirectX-based image transformation, with light-gray color (#CCC) directed 3 pixels to the lower right (direction is in degrees clockwise from the vertical). I chose the color to more closely imitate the effect of the blurred shadow in the standard CSS method, but ultimately they are different effects: Standard CSS3 places a copy of the text and blurs it, while the DirectX filter appears to extend a solid prism in the appropriate direction, without blurring; also, unlike the CSS3 method, the DirectX disables font smoothing and is limited to 8 directions.

Box Shadows

Box shadows can be achieved via the box-shadow: CSS property with a similar syntax to text-shadow in Opera 10+, Firefox 3.5+, Safari 3+, and Chrome (or at least they should be achievable, more on that below), and in IE5.5+ via the same filter as for text shadows, and here the effect is more pleasant; unfortunately it does not work in Konqueror, iCab, or versions of Opera before 10.

If your browser supports box shadows, you should see one here.

Box shadows work in IE just the same way as text shadows, and clearly the Shadow filter was meant for boxes because the type of shadow is like a shadow from a broad object and because this shadow, when applied to an object with a non-transparent background-color, does not affect font smoothing (except in IE8); meanwhile there is no browser that actually supports the CSS3 property because it is too experimental (CSS3 itself is not yet finished). Instead each layout engine uses a vendor-specific prefix for experimental properties awaiting standardization: Opera uses -o-, browsers like Firefox built on the Mozilla Gecko engine use -moz-, browsers like Konqueror built on KHTML use -khtml-, browsers like Safari and Chrome built on Webkit use -webkit-, and Microsoft uses -ms- for IE for Windows; to my knowledge neither IE Mac nor iCab 3 ever used vendor-specific prefixes (the final version of IE Mac was released in 2003 and the browser was officially retired in 2006, while iCab 3 was last released on 1 January 2008 and the current iCab 4 runs on Webkit).

In case it sounds as if the browser wars of the 1990s have returned, fear not, for this is rather a browser race, with the various manufacturers implementing new features in CSS3 and HTML5 as soon as the end is in sight for their eventual standardization in order to maintain a progressive image in the minds of developers and the Web-savvy public and to collectively allow for the sustainable evolution of the Web, instead of a fierce competition in which each participant desires to achieve total control of the Web via vendor lock-in to proprietary innovations; Microsoft's sluggishness in this race is partially compensated by the numerous workarounds available via its old proprietary methods, including its greatest innovation of all: conditional comments. The current way to achieve state-of-the-art layouts across the widest possible range of browsers with only CSS involves a great deal of repetition of code (the 5 vendor-specific prefixes followed by the future standard name) and the possible addition of old Microsoft filters, and although it makes stylesheets bulky and does not validate, it is the only way to go; it is reminiscent of table-based layouts and presentational markup before the advent of IE6 although not quite as difficult to maintain.

Right-Angle Text Rotation

Firefox 3.5+ and Safari 3.1+ have experimental support for transform, and one of the ways to transform text is rotation; meanwhile IE5.5+ has two different methods, and one is the BasicImage filter, which only allows rotation by quarter-turns.

Going Up

The positioning is so different between IE8 and earlier versions and between IE and the CSS method that conditional comments are needed in production use.

General Text Rotation

The transform property in Firefox 3.5+ and Safari 3.1+ allows general rotations; meanwhile IE5.5+ needs to use the Matrix filter, which allows any linear transformation, including rotation, represented with a 2D square matrix. This is implemented in wildly different ways between IE8 and earlier versions and differs so vastly from the CSS3 rotation with respect to repositioning (to keep the text from overlapping other paragraphs) that this requires numerous conditional comments to be useful.

This is a story all about how this text got flipped, turned upside-down...

The syntax for CSS3 is rotate(t), which rotates the text clockwise by t (in this example it is -170 degrees). To get this functionality with filter:progid:DXImageTransform.Microsoft.Matrix() you will need to put inside the parentheses the elements of a 2D rotation matrix; if t is the intended angle of clockwise rotation, the elements would be M11=cos(t),M12=-sin(t),M21=sin(t),M22=cos(t), and I believe you will need to compute the trigonometric functions beforehand, whether hand-coding or using scripts (which will be useful when animating rotations, a technique with even less support as pure CSS than static rotation). As before, any filter applied to text disables ClearType, and when using a general rotation the text is smudged; the Firefox implementation is very shaky (the text literally shakes when you select it), while Safari handles rotation well, which should be expected because support first appeared in Webkit nightly builds late in October 2007. On another note, the latest Webkit nightly handles 3D CSS transformations, but the implications for usability prevent them from ever being recommended; the Web is not a video game and should not be treated as one.

Ruby Text

Ruby text consists of small explanations above individual units, like the pronunciation and meaning of a very common Japanese word: (desu)(form of "be"). Another example is a way to show the current month: Mar(2010).

Simple ruby annotation is achieved as in the second example by enclosing one rb (ruby base) element followed by one rt (ruby text) element inside a ruby element, with one or more rp (ruby parenthesis) elements interspersed; the rt element is is usually rendered in small type directly above the rb element, and the rp elements are hidden and normally enclose parentheses that are only displayed, much like the noscript element, by browsers that do not understand ruby annotation, as a fallback mechanism. More complex ruby annotation encloses at least one rb element in one rbc (ruby-base container) element followed by one or two rtc (ruby-text container) elements each containing enough rt elements, weighted by their rbspan (ruby span) attributes, which denote how many base characters to span, to equal the number of rb elements; the first rtc element is rendered above the rbc and the second, if it exists, below, and as before any rp elements present will not be rendered except as a fallback by browsers that do not understand ruby annotation.

Ruby annotation is like a small inline text-table and is part of XHTML1.1 but only implemented by IE5+ (Windows and Mac), which is unusual given the refusal of IE to render XHTML with the proper MIME type application/xhtml+xml and more general lag in standards support and may explain the relative popularity of IE in Asia, although there are an extension for Firefox 2+ that adds support for proper ruby markup, a simpler extension for Firefox 3+ that is more forgiving of invalid markup yet not quite as powerful, implementations of the latter as a Chrome extension and an Opera UserJS, and a stylesheet used here that lets any browser display the markup; whether using the native IE implementation or the CSS, multiple ruby texts are not implemented correctly and it is only safe to use simple annotation, but the first Firefox extension renders ruby text perfectly (although it also displays title attributes of abbr elements and the like by default; be sure to turn that off). Specific ruby-display properties are in the works for CSS3 too, but they are only implemented by those versions of IE that understand ruby annotation to begin with.

Not Quite Ready

These text effects require workarounds unavailable in stylesheets, like Javascript or alterations to the HTML, in order to reach most users.

Rounded Corners

At first, the way to make corners rounded was with tables and corner GIFs made for each pair of colors (foreground and background), and later with semi-transparent PNGs combined with the AlphaImageLoader filter for versions of IE below 7; now there is a cross-browser technique with Javascript and CSS called Nifty Corners, but a pure CSS method needed to wait for experimental adoption of border-radius by Firefox 2, Safari 3, and Konqueror.

If your browser supports CSS3 rounded corners, you should see them here.

The basic code here is border-radius:5px; and it is also possible to specify elliptical corners, first the horizontal semiaxis and next the vertical semiaxis, and settings for each individual corner; negative radii are forbidden.

This box should have an elliptical corner at the top-left and a round corner at the bottom-right.

Note that support is so spotty and CSS3 finalization so far-off that the browsers that do support individually-rounded corners do not even follow the same naming convention; Firefox uses, for example, -moz-border-radius-topleft instead of something based on border-top-left-radius. Also, Firefox 2 and 3 did not support elliptical corners and therefore had no trouble with the evolving CSS3 specification for border-radius when two parameters are supplied, using the first parameter for the topleft and bottomright radii and the second parameter for topright and bottomleft; Konqueror does this too, but Safari draws elliptical corners all around.

Two sizes of rounded corners should be shown, but Safari shows elliptical corners all around.

An ambiguity arises for Safari when 4 parameters are used: Should they be used as the semiaxes for alternating elliptical corners or as the radii for each individual corner?

The parameters are 10px 5px 15px 20px.

Safari does not permit more than two space-separated parameters to border-radius, and neither did the CSS3 Border Module in 2002 (although it does now), while Firefox since version 2 has seen no ambiguity and interpets the parameters in the order topleft, topright, bottomright, bottomleft; it should be possible to specify the semiaxes of elliptical corners in two sets of space-separated parameters, separated by a forward slash...

The parameters are 20px 5px/15px 10px.

Firefox 3.5+ and Konqueror follow the standard more closely than Safari in allowing slash-separated sets of space-separated parameters for border-radius; finally, when three parameters are used, they are interpreted much as three parameters in other shortcut properties: The first one is for the topleft, the second for topright and bottomleft, and the third for bottomright.

The parameters are 10px 5px 15px.

Sadly, until Internet Explorer implements border-radius, Nifty Corners remains the best solution for rounded corners in IE5.5+ and other browsers without resorting to images and tables; on another note, multiple background images could be used, except that support is even less widespread than for rounded CSS corners (only Webkit, since Safari 1.3+, and Konqueror have implemented it, although it is in the pipeline for Firefox 3.6).

Not Recommended

Whether widely available in CSS or not, these should be used sparingly if at all.


Webkit and Presto support transition experimentally (Gecko has limited support), and although I won't show this off, a demonstration of animation shows the potential for abuse: Imagine advertising of the future with a close-button that transitions toward a translation 9999px left whenever the :hover pseudo-class applies; you would never be able to close it, and blocking scripts would be useless against it!