Strange Medium

Digging up a very old blog entry from http://www.456bereastreet.com/archive/200408/sizing_monospaced_fonts/, the question is asked, “What’s up with the different font sizes when the monospace font family is used?” The answer, as usual with Web browsers, is pretty interesting (which is browser developer-speak for “insanely confusing”).

The default font size displayed in a Web browser is a logical one, the CSS keyword medium. Some browsers use other logical size keywords for the default font size in quirks mode (essentially an off by one difference), but the idea is still the same: that no absolute font size was specified. Instead the font size is left up to the browser engine to determine based off the user’s settings. The problem with logical keywords like medium is that they don’t just map to a single user-defined value.

Try pulling up the Safari preferences and head over to the Appearance panel. You will see that you can fill in information for both proportional and fixed width fonts. The typical default font size is 16px for all proportional fonts and 13px for all monospace fonts. This is the key concept to keep in mind as we plunge ahead, that the ability to specify unique default font sizes based off family type leads to ambiguities in terms of what the CSS font size keywords actually mean.

Here’s a simple example:

<div style=”font-size:medium”>Hello world without fixed pitch. <tt>Hello world with fixed pitch</tt></div>

Assuming that you haven’t changed your default settings, what you should see in the example above is a 16px proportional “Hello world without fixed pitch” message followed by a fixed pitch “Hello world with fixed pitch” message that is only 13px tall! The sizes are different, so what happened? Doesn’t CSS say that font sizes should be inherited?

In order to honor the user’s preference settings for monospace, browsers will attempt to adjust the size to fit the monospace preference. In effect, what is inherited isn’t a value of 16px, but rather a logical size of medium that morphs in value depending on whether or not a generic family is used.

The most basic examples of this strange inheritance are <pre> and <tt>, which are both defined to have font-family: monospace in modern browsers’ user agent style sheets. Thus in the absence of any explicitly specified size, the browser must make an adjustment to honor the user’s settings. These basic examples are interoperable.

In other words you could reformulate the previous example as follows and get the same results:

<div style=”font-size:medium”>Hello world without fixed pitch. <span style=”font-family: monospace”>Hello world with fixed pitch</span></div>

Because the rules for when a browser should make this size adjustment are unspecified, it has been left up to the respective engines to decide when and how to make these adjustments. The “bug” cited in the blog entry above stems from WebKit’s decision to make this size adjustment in a situation where other browsers decided not to.

The specific example in the bug basically boils down to this:

<div style=”font-size:medium”>Hello world without fixed pitch. <span style=”font-family: Courier, monospace”>Hello world with fixed pitch</span></div>

This example is almost identical to the previous one. The only difference is the presence of a specified named font prior to the use of the monospace generic family. WebKit looks at that font-family declaration and assumes (correctly) that the font used is a fixed pitch font. Therefore the engine adjusts the logical value of medium to match the user’s monospace size preferences. In this particular case, other browsers do not make the adjustment.

Consider this example:

<div style=”font-size:medium”>Hello world without fixed pitch. <tt style="font-size: larger">Hello world with fixed pitch</tt></div>

Here we have a medium proportional font and a monospace font that has been specified as being “larger.” The question of how to determine the correct size now depends on whether the browser engine decides that “larger” means “take 16px and make that bigger” or “take medium and make that bigger.” This example turns out to be fairly interoperable, with Opera, Firefox and Safari all choosing the latter definition. Therefore the fixed pitch font ends up being about the same size as the proportional font that it inherited from.

Of course this adjustment doesn’t just happen in one direction. Consider the reverse example.

<tt style="font-size:medium">Hello world with fixed pitch. <span style="font-size: larger">Hello world without fixed pitch</span></tt>

There are many more interesting examples, though, and interoperability starts to suffer as the ambiguities in when to apply an adjustment are exposed. Here is one such ambiguity:

<tt style="font-size:medium">Hello world with fixed pitch. <span style="font-family: Times">Hello world without fixed pitch</tt></span>

When a font face is explicitly specified, but no generic family is specified, what do you do? In Safari 2, Firefox 1.5 and Opera 9, no adjustment is made, and so the proportional font does not get any larger. In WebKit nightlies, we go ahead and assume that a font-family with no generic family specified should use the proportional font size setting, and so we do make an adjustment.

Otherwise you could end up with an example like this, where making an adjustment is obviously incorrect, and yet Safari 2, Opera 9 and Firefox 1.5 all do so.

<tt style="font-family: Verdana; font-size:medium">Hello world without fixed pitch.</tt>

Of course one could make the counter-argument that the actual fonts in the family list should be examined in order to decide if the family list taken as a whole is fixed or proportional, but this is problematic at the time the cascade is being done. This is why WebKit in the nightlies now just uses the first generic family in the list as a guide, and if no generic family is present, it will err on the safe side and assume proportional.

The moral of the story: be wary of tt, pre and font-family: monospace.