Font-adjust: a CSS enhancement proposal

Author: Todd Fahrner, Verso
Last modified: 15 December 1997

For any element, CSS allows specification of a list of typefaces in order of preference. Later chosen faces will be substituted when earlier ones are not available. In the event of font substitution, however, font size, line height, and font weight do not adjust to preserve the general legibility, readability[1], and aesthetic characteristics of the first-choice grouping. This is a crude gap in an otherwise elegant system to express aspect-, resolution-, and font-independent typography.

[ Let's have some pictures! - Exhibit a  ·  Exhibit b ]

The unadjusted results of font substitution are often unacceptable, and constrain the set of prudent typeface specifications in CSS to a very narrow band in the typographic spectrum: to Times, Arial/Helvetica, and perhaps to some of the fonts Microsoft has made freely available. (This last group's unusually high legibility at small sizes can make substitutions especially unfortunate, however.)

To address these problems, I propose a new CSS property: font-adjust. If font substitution occurs, font-adjust applies simple algorithmic transformations of the originally specified font size, line height, and font weight to the substituted font, to help preserve a reasonable approximation of the first-choice font's appearance, both at the character level and in mass.

Font-adjust is shorthand for three properties: font-size-adjust, line-height-adjust, and font-weight-adjust.

Property Name: font-size-adjust
Value: none | z (see explanation)
Applies to: all elements
Initial: none
Inherited: yes, but not the adjusted values

The effect of font-size-adjust is to preserve the ex-height of the first choice font in substituted fonts. The value z refers to the ratio of em- to ex-heights of the "first choice" font in decimal notation. (Mnemonic: em/ex: eczema - note inversion.) For example, the popular font Verdana has a z value of 1.72; in an instance of Verdana at 100 pt (em-height), the ex-height will be 58 pt. 100/58=1.72. For comparison, Times New Roman has a z value of 2.17.

Font-size-adjust uses z to compute an appropriate scaling factor for available fonts, according to the following formula:

	a(z'/z) = b


	a = font-size of first-choice font	
	z' = z of available font
	b = font-size to apply to available font

The subjective "bigness" and general character of a font on screen is less dependent on the size of its em than on the size of its ex, or, more usefully, on its z. The lower the value of z, the more legible at smaller em sizes it will likely be. Inversely (and more to the point), faces with a higher z value will become illegible more rapidly below a given threshold size than faces with a lower z. Substitution can easily fall foul of this threshold.

Exhibit a shows several typefaces as rasterized on a Macintosh at 12 point, together with their z values. No matter what the typographical family (or nominal base size, unit, or platform), faces with lower z look bigger than those with higher. Faces with very high z are illegible at the size shown.

Exhibit b shows the results of font-size-adjust with the fonts shown in exhibit a. These fonts' em sizes range all the way up to 25 pt, but appear subjectively to be about as large as 12-pt Verdana, whose z served as the base for scaling. As adjusted, the legibility characteristics of these faces on screen are nearly linear across faces. Note that font-size-adjust tends to stabilize the horizontal metrics of lines, as well.

You may be thinking: "the fonts in both exhibits look pretty bad." You may prefer to see the same items in a scalable, anti-aliased format (78K PDF), courtesy of Adobe Acrobat 3.

Property Name: line-height-adjust
Value: none | normal
Applies to: all elements
Initial: none
Inherited: yes

Normally, the initially specified or inherited font-size value will apply when determining line-height as a function of font-size. However, when line-height-adjust is declared "normal", the computed result of font-size-adjust will be taken (inherited) as a base for determining line-height.

Note that the initial value of "none" for this property will favor the typesetting principle that faces with a low z value require more leading on lines of given length than faces with high z values, because generous ascenders/descenders represent "built-in" leading.

Property Name: font-weight-adjust
Value: none || 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
Applies to: all elements
Initial: none
Inherited: yes

Font-weight-adjust takes as its value the weight of the first-choice font. Should font substitution occur, and the adjusted font-size vary more than 1/9th (11%) from the first-choice value, the font weight will be adjusted to the corresponding increment along the 9-step scale. Font-size increases will produce font-weight decreases, and vice-versa. This will serve to preserve the color balance (light/darkness) of the text after font substitution.

Property Name: font-adjust
Value: [ <font-size-adjust> || <line-height-adjust> || <font-weight-adjust> ]
Applies to: all elements
Initial: not defined for shorthand properties
Inherited: yes, but not the adjusted values

Shorthand notation for all three "adjust" properties.

[1] On the difference between legible and readable, see this Usenet message, in which the author gets corrected for confusing the two.