Notes toward a CSS-savvy browser UI

Author: Todd Fahrner, Verso

Among other things, web browser user interfaces enable users to customize the formatting of Web pages to suit their needs and preferences. Until CSS, there was no standard way to describe such needs and preferences, nor any standard means of resolving conflicts between user and page author formatting suggestions. Cascading Style Sheets are so called because they comprise mechanisms to resolve conflicts among declared styles - user styles, author styles, etc. While the cascading algorithm is well-defined in the specification, user interface to the cascade is not. It's up to implementors to devise an appropriate UI. This document discusses one.

David Baron has prepared some excellent complementary work.


15-20 years ago, as "WYSIWYG" word processing and desktop publishing started to become popular phenomena, many people were confronted for the first time with concepts like "font menus", "point sizes", and "leading". For a time, typewriter-centric notions like "10-pitch", "tab stops" and "double spacing" coexisted uneasily with the less familiar, more powerful concepts, often to the detriment of effective usability.

Now, just as "10 pitch" is beginning to sound quaint to us, we are challenged to deal with yet another typographic paradigm and its essential vocabulary: that of the Web page. Page widths and heights, author-defined fonts and colors, physical measures like points or inches, and other print concepts are no longer so absolutely pertinent. This time, author and reader responsibilities for the rendering of a document are interleaved. The reader must to some extent engage the author/designer's vocabulary in order to have the least helplessly submissive experience - to interact.

I believe that as more and more information is shared globally by electronic textual means, an understanding of electronic textual display issues becomes more and more fundamental a part of literacy. As CSS is emerging as the standard model for making structured electronic texts fit for human consumption - for Web typography - the user interface of Web browsers should evolve to exploit CSS as such.

Basic concepts

Before CSS (and even in today's first- and second-generation CSS implementations) the final rendering of an HTML element was determined typically by (a) the browser's hard-coded defaults, (b) a small set of font, size, and color preferences exposed to the user, and (c) formatting instructions (e.g., font tags) included in the document by the author. Some browsers provided a means for users to override author formatting in a few respects, either persistently (through the preferences) or transiently (through, say, a font-size button). Let's label these override functions (d), and call this whole system "the old model".

CSS's new model comprises analogous elements. These are (a) the UA default stylesheet; as well as accommodation for (b) one or more user stylesheets, and (c) one or more author stylesheets. These correspond to the identically labeled elements in the old model. The CSS specification suggests an equivalent of (d) in the form of !important modifiers. This element may be understood simply as a class of user stylesheets suited for more assertive application, quickly and transiently through a "top-level UI" gesture rather than a "configuration" step.

To date, implementations of the new model have neglected one or more of elements a, b, and d. The old model has been maintained in place alongside partial support for the new, leading to a large abscess of undefined behavior in the document rendering equation, and growing frustration for Web users and authors alike.

Below is a schematic and worked example of the new model in action. It uses font-size on the BODY element merely to illustrate a commonly adjusted style rule. The same dynamic applies with any other markup element/CSS property, such as text/background/link colors, the visibility of images, or margin and indent properties on the P element:

   |    a |    * user viewable/editable, yet restorable to default state
   |      |    * minimal or no ui access (for power users only)
   |ua.css|    * contains media-specific blocks; all defaults/initial values
   |      |    * values should become de facto standard per media type
   |______|    * typical content: "body {font-size: 12pt}"

      |          applied body text size: 12pt

    __|___   | * (b) imports ua.css; others may optionally import (b)
 __|___   |  | * sheet (b) exists by default; others by user choice
|    b |  |  | * prefs UI values stored in (b) - colors, fonts, sizes,
|      |  |  |   link indication, image display, !important, etc.
| user |  |__| * one-step UI needed to switch among secondary user sheets
|.css  |__|    * typical content: "body {font-size: 12px}"
|______|         (interpolated from user choice of "9pt" and 96 ppi setting)

      |          applied body text size: 12px (overrides ua.css)
    __|___   |
 __|___   |  |
|    c |  |  | 
|      |  |  | * standard cascading rules apply wrt user/ua.css
| auth.|  |__| * typical content: "body {font-size: 8.3pt}"
|.css  |__|
                 applied body text size: 11px
      |          (interpolated from "8.3pt" and 96 ppi setting)
      v          (overrides user.css)
    __|___   | * cascaded in by one-step UI; e.g., size button
 __|___   |  | * transient - de-cascaded upon leaving current domain
|    d |  |  | * typical content:
|trans-|  |  |      body {font-size: 112% !important}
| ient |  |__|         * {font-size: inherit !important}
|.css  |__|

                 applied body text size: 12px
                 (overrides author.css)

Note: stylesheets a, b, and c are described in the specification; I have introduced the notion of transient stylesheets. They do not necessarily differ from User stylesheets formally, but in the typical mode of user application and the "stickiness" of said application. So I distinguish between Persistent User stylesheets (applicable through a preference dialog) and Transient User stylesheets (applicable through top-level UI).


The sketches below are based on MacIE4.5's UI, and were first publicized on a MacIE mailing list. The feature set is intended to be suitable for cross-browser, cross-platform implementation, however. Their focus is not the look, feel, exact wording, placement, or arrangement of user interface elements, but instead the functionality they should collectively offer.

Preference panel interface to a persistent user stylesheet

This covers only fonts and sizes; others might cover colors, image prefs, alternate user stylesheet addresses, etc. Ambitious CSS editing will best be left to dedicated editors.

preference panel

A user stylesheet could record all of this info, e.g.:

 1  @font-face {
 2   font-family: "serif";  /* the generic category from the prefs */
 3   src: url(""); /* Georgia, online/cached */
 4   units-per-em: 100;
 5   x-height: 50;  /* ua.css could ship with correct values for
 6   }                 popular fonts; authors could add/edit */
 8  @font-face {
 9   font-family: "monospace";
10   src: url("resource://Monaco.ttf");
11   units-per-em: 100;
12   x-height: 46;
13   }
15  html { 
16   font-size: 16px;	/* interpolated from "12pt" and 96ppi */
17   font-family: serif;
18   font-size-adjust: .5 inherit !important;

So, if a span of "monospace" with an x-height of 46 (line 12) were to occur within a span of "9pt serif" with an x-height of 50 (line 5), and font-size-adjust were implemented in the UA, the size of the monospace font could be adjusted upward to 10pt, to look the same size as the 9pt serif around it. 9(50/46) = 9.78. Otherwise the monospace span would appear to be about 10% smaller than the surrounding text, which will quite possibly render it illegible at, say, 72ppi. Here's an elaboration.

It is important to capture both x-height and display resolution information in order to assure that bicameral fonts which are expected to remain legible do not have x-heights resolving into fewer than 5 pixels:

    5       xx   xxx  xxx
    4     xx  xx   x  x
    3     xxxxxx    xx
    2     xx       x  x
    1       xxx  xxx  xxx

You can't rasterize these characters into fewer vertical pixels without munging the "e". The inability to determine the font size at which munging occurs for arbitrary fonts is a major problem, especially cross-platform. If you know the real value of ex and enough about the display, you can compensate for any unit system.

Top-level interface to a transient user stylesheet

top-level UI

Example CSS binding of "scale:112%":

body {font-size: 112% !important}
* {font-size: inherit !important}

Why these intervals? Simple harmonic intervals produce the best scaling results, because low-number denominators stand the best chance of factoring evenly into any bitmapped element's native pixel count (such as an image to be zoomed, or a bitmap font to be interpolated):

keywords    %   @96ppi  ratio
          200%   32px   2/1      }
          167%   27px   5/3       } zooming range (mod. toggles fonts-only)
xx-large  150%   24px   3/2      }
 x-large  125%   20px   5/4  }
   large  112%   18px   9/8   }
  medium  100%   16px   1/1    } font-size-change range (mod. toggles zoom)
   small   89%   14px   8/9    }
 x-small   75%   12px   3/4   }
xx-small   60%   10px   3/5  }

The scale is an extended pentatonic (6-step) scale where 100% is unison and 200% the octave. This is the Mosaic UA's hardcoded BODY-H1 interval. See Just vs Equal Temperament for background on harmonic interval systems. Though derived from a system proven pleasing to the ear, the same intervals prove pleasing to the eye, and are practical to boot. Traditional typography and tonal music have both long borrowed from natural sources in the development of their interval systems.

Top-level interface, cont.

top-level UI, cont.


Don't miss the meaty thread growing on Mozilla's news server about this. Wouldn't it be cool if both Mozilla and Microsoft were to adopt some of these ideas?

The following is excerpted from other correspondence on this heading:

Related/background rantings:


> I wonder though, if all of this would not go away through the simple
> expedient of changing the font-size button to a zoom button?

My explanations are thin, but I do envision that functionality for the
top-level UI, represented in the second and third GIFs. This could just as
easily be invoked through a button as through a menu.

As I see it, though, it will not be desirable to scale everything, all the
time, by arbitrary increments - visual quality and performance problems.
For small adjustments, magnification won't be worth it. And simply scaling
everything by the same increment sidesteps the root issue that pixel objects
(GIFs, tables, etc.) and fonts are based in uncoordinated unit systems:
pixels and points.

So the first part of the solution is to remove as much of the impetus to
scale as possible: synch up the default logical resolution across platforms
to 96ppi (like Windows). As shown in the first GIF. This can of course be
overridden - indeed it can be set to arbitrary intervals to reflect actual
physical resolution. If the OS's won't do it, the browsers must.
Cross-platform interoperability is at stake.

The second part of the solution is to implement CSS2's font-size adjust
property (
) in user stylesheets, for local resident fonts. This way it will not be
necessary to specify preferred sizes for each and every candidate font: they
will all be adjusted to have the same ex-height as the user's default font
at any given size.

Sometimes it will be desirable to magnify pixels after all - as when using a
very high resolution display or making a presentation. So the third part of
the solution is to let the user set a "pixel object scaling threshold". This
sets the point at which the "scale" button/menu becomes a true zoom
function, affecting pixel-specified objects as well as type.

Users could use a modifier (option key) to toggle between whether the scale
button acts as a text adjuster or an all-around magnifier - see "Override
pixel scaling threshold" - third GIF.

> Then, if people want to specify 7pt type, so be it. This also must make
> printing a lot more rational (7 pt CSS goes to 7 point postscript on the
> printer and whatever-size-you-like in your zoom-enabled browser). It is
> also consistent with the approach of many other Mac apps which must deal
> with details which only resolve on screen at certain scales.

(semi-sequitur): Traditionally, Mac apps have scaled pixels to print to
1/72", regardless of their "zoom state" on screen. Netscape has printed
pixels (as in GIFs or tables) at 1/120" - an attempt to compensate for
Windows' general brokenness in this area. W3C recommends standardizing upon
1/90". So the pixel scaling threshold described above should operate
relative to 90ppi, rather than to whatever the specified logical resolution

> The answer certainly is not to forbid or coerce certain styles,

Sure - that's why the live preview is in the preference panel: it gives fair
warning of how xx-small will look when "medium" is n points in the chosen
font. Or would you forbid/coerce me from forbidding/coercing certain
conditions in my user style sheet? ;^)

> nor to
> special-case the renderer to death.

It's already in its death throes, trying to solve too many problems with too
few and the wrong hammers. If the UI I'm describing is complicated, it could
be broken into more screens, some of them marked "advanced."

The various preference dialogs should read/write as much of their data as
possible from an editable user stylesheet, IMO. Power users will want to
edit a user stylesheet directly, I expect, to address many of these issues
with @font-face rules, etc; imposing as many "coercions" and "special cases"
as CSS can express.


> The preference panel is just missing font sizes. I want 12pt Stone Informal
> for proportional and 9pt ProFont (v2.2:-) for monospace, f'rinstance.

That's what the "adjust font sizes to look like my default" would do,
more-or-less. It would apply the CSS-2 font-size-adjust algorithm to fonts
other than your default, resulting in "same size" looking fonts: .

Rather, if you truly wanted your instances of monospace to look smaller than
your instances of "proportional" (a category superseded in CSS by serif,
sans-serif, script and "fantasy"), you would have a line in your personal
stylesheet selecting the target markup elements (PRE, TT, CODE, KBD, etc.)
and apply "font-size: small" or whatever. But you need the ex-height
normalization (font-size-adjust) for this to have predictable results.

>>So the first part of the solution is to remove as much of the impetus to
>>scale as possible: synch up the default logical resolution across platforms
>>to 96ppi (like Windows). As shown in the first GIF. This can of course be
>>overridden - indeed it can be set to arbitrary intervals to reflect actual
>>physical resolution. If the OS's won't do it, the browsers must.
>>Cross-platform interoperability is at stake.
> How would this be done -- just auto-scale up font sizes so that 9pt-speced
> fonts will be taken as 12pt fonts?

More or less that, yes. 1pt=1.3333 pixels. Mac/Win parity. Note that this is
in fact closer to "accurate" for a great many Mac users. See the example
resolutions given for 96/72ppi in the first GIF.

> The [A^] button is supposed to do that,
> but as we've learned it sometimes does not function at all.

I disagree. Type speced in either points or pixels should not generally be
scalable unless the entire layout and all its objects scale together, a la
PDF. Type specified in relative units (ems, percentages) or keywords
("medium", "large", etc.) should be freely scalable. There's a thread about
this in the www-style archive, with this conclusion.

As a matter of authorial practice, I think it's generally better to use
relative/keyword measures. But until the XP base rasterizations are synched
up, few "designers" can tolerate the gratuitous variance this produces. So
they lock everything down in fixed units. Pity. Nevertheless, if fixed units did not
exist, they would have to be invented.


>>Rather, if you truly wanted your instances of monospace to look smaller than
>>your instances of "proportional" (a category superseded in CSS by serif,
>>sans-serif, script and "fantasy"), you would have a line in your personal
>>stylesheet selecting the target markup elements (PRE, TT, CODE, KBD, etc.)
>>and apply "font-size: small" or whatever. But you need the ex-height
>>normalization (font-size-adjust) for this to have predictable results.
> Actually, I don't want "small" I want EXACTLY 9pt ProFont for monospace,
> which comes to exactly 480px wide for an 80-column line of <pre>. So I
> think PRE { font-family: ProFont,Enclave,Monaco; font-size: 9pt } should
> be predictable enough if the browser respects it. But I don't want it to
> be scaled to 12pt in any +33% 96/72 adjustment -- I want it to be the
> final word,

Then what you really want is not 9pt but 9px. And !important to override
authors' CSS to the contrary:

PRE { font-family: ProFont,Enclave,Monaco; font-size: 9px !important }


> Under "A Proper CSS Browser's Prefs", why the radio buttons for ppi?
> Shouldn't this simply be a function of the current monitor size and
> resolution?

OS's typically don't know this - what's worse, they make invalid assumptions, so 
users/UAs must step in. Users may have good reasons for not wanting "true WYSIWYG" 
anyway, so it should be discretionary. As for why the dialogue doesn't solicit 
display dimensions and pixel counts directly - probably the same reason printers 
are sold as "1200dpi" rather than " 11"x17"x13200x20400 " Brevity, clarity, habit.

I think the XP default should be 96ppi, in concession to the reality that
there are a whole lot of Windows-based authors who don't know the difference
between a point and 1.33333 pixels.

> And what exactly does "pixel object scaling threshold" do?

As you and I have discussed, Braden, CSS1 recommends that UAs scale pixels
when the output medium resolution varies "significantly" from that of a
"typical" computer display. It goes on to suggest a "reference pixel" of
1/90" as the basis for scaling to the new device resolution.

"Pixel object scaling threshold" sets the point at which this scaling kicks

So if you're using a 180ppi display in 4 years, and you're viewing a
1996-99-era GIF-and-table HTML confection, and you've got your scaling
threshold set to 199%, your UA should scale all pixel objects by 200%.
Similarly, when you print said page to a 300dpi printer (even today), each
GIF/table pixel should translate to 3.3333 printer pixels.

If you wanted to print the GIF/table thing at the printer's resolution, you
could crank the pixel scaling threshold up to 900% or so, or override in
some print dialogue or other.

But it's not just to get ready for sci-fi display scenarios or control-freak

In addition to the preference dialogs, there must be handy top-level UI to
adjust a page's visual scale. But for performance and visual quality
reasons, it will not be desirable to scale all page objects by small,
arbitrary intervals - certainly not before we're in vector graphics land.
No, what people want to do most of the time is crank the font size up or
down a little - that's all.

So the top-level UI would affect only font sizes *until* the adjusted font
size reached the specified pixel-object scaling threshold. At which point
all page objects would scale, to help keep the layout from breaking.

Option-accessing the same UI element could override the current
pixel-scaling threshold and magnify everything by the desired factor. Like
Opera's zoom function.


> I'm still somewhat confused about the font-size-adjust example that you
> gave. Could you tell me what the HTML and CSS look like for that
> example?

I assume you mean the part starting "So, if a span of "monospace" with an
x-height of 46 (line 12)...."

I don't assert that the behavior I describe falls naturally out of the spec,
and I admit that I can only see so far into the murk. Rather, it's probably
an extra feature that leverages CSS properties and syntax, hopefully without
getting in the way. But in case your question is more elementary, here's an
elaboration of the example given:

example html:

    <p>This is the expression: <code>[a-z|# ](.+)</code>.</p>


 1  @font-face {
 2   font-family: "serif";
 3   src: url("");
 4   units-per-em: 100;
 5   x-height: 50;
 6   }
 8  @font-face {
 9   font-family: "monospace";
10   src: url("resource://Monaco.ttf");
11   units-per-em: 100;
12   x-height: 46;
13   }
15  html {
16   font-size: 16px;
17   font-family: serif;
18   font-size-adjust: .5 inherit !important;
19   }
21  cite {
22    font-family: "monospace";
23    }

author css:

    p {
     font-family: Paraquat, Leatherchimp, Times, serif;
     font-size-adjust: .44;

Line 18 of the user/ua.css above means "make sure that all of HTML's
children at "1em/medium" have 8 pixels available for the x-height, adjusting
the actual font size up or down as necessary to accommodate varying font
designs, regardless of whatever font-size-adjust data the author may have
provided." An element at "2em" - say H1 - would therefore be scaled as
necessary to have a 16px ex-height, while an element at .83em would have a
6px ex-height (rounding off).

So... the author has specified his/her preference for two unknown fonts
named Paraquat and Leatherchimp. All we know about Paraquat is that its
aspect value is .44. We do have the Times font, and because it's local and
we've analyzed its metrics (or perhaps Mozilla ships with a font metrics
database), we know that its aspect value is .46. Since the user has not made
his/her choice of "serif" "!important", we'll use the author's #3 suggestion
of Times. Assuming that P is to render at 1em/medium, we calculate Times'
font size as follows:

50/46 * 16px = 17.39px

So we render Times at 17px. It will look just as big as our personal
favorite of Georgia at 16px, because its ex-height will be the same.

Now about that CODE element. The author hasn't specified anything about it,
so we'll use our default of Monaco. Because no special size has been
specified for CODE, we'll use the parent element's size: 1em/medium. Since
Monaco has an ex-height of .46 like Times, the math to determine the right
size of CODE is the same:

50/46 * 16px = 17.39px

So we render Monaco at 17px. Both the paragraph in Times and the sub-element
CODE in Monaco look the same size as our first choice, 16px Georgia.

Why not join the discussion?