David Baron's Weblog

Some new CSS features in Firefox 3

Friday, 2008-06-13, 14:52 -0700

Our developer documentation already has a list of the new CSS features in Firefox 3. I'd like to talk in some more detail about some of the more interesting or useful ones.

inline-block and inline-table

We now support the inline-block (CSS 2.1) and inline-table (CSS 2.0) values of the display property. These values map to formatting objects that are like blocks or tables on the inside, but participate in inline layout.

Here's a simple example (see HTML) that actually demonstrates both values:

[SCREENSHOT]

This example may not look all that interesting, but I think these properties will end up proving more useful in complicated situations, where having these additional basic tools will help authors get the layout they want. This was also a value where we'd been lagging behind other browsers and we've now caught up, so inline-block should actually become usable to authors writing Web pages for multiple browsers in the near future.

Note that the default value of vertical-align is baseline. Baseline-alignment for inline-blocks refers to the last line of the block, while baseline-alignment for inline-tables refers to the first row of the table. Many uses of both may need other values for vertical-align.

font-size-adjust

font-size-adjust is a property in CSS 2.0 (which was dropped from CSS 2.1 due to lack of implementations), originally proposed by Todd Fahrner. There are a few different ways to think about what it does, but the way I like to think about it is that is a way for style sheets to pick font size by the size of the x-height rather than the size of the font. This is useful for languages like English that have bicameral scripts (i.e., have both uppercase and lowercase letters); it's probably a bad idea to use it for Chinese.

Since there are existing browsers that don't support font-size-adjust, it has to do this in a backwards-compatible way. So the way it works is that the author specifies a number that is multiplied by the font size:

    font-size: 20px;       /* 20px font in old browsers */
    font-size-adjust: 0.6; /* 12px lowercase letters in new browsers */

Having it work a multiplier is also useful because it doesn't need to be respecified on a child with a smaller font size:

    body {
        font-size: 24px;       /* 24px font in old browsers */
        font-size-adjust: 0.5; /* 12px lowercase letters in new browsers */
    }

    p.copyright {              /* the "small print" */
        font-size: 75%;        /* 18px font in old browsers */
        /* lowercase letters are now 9px new browsers, no need to respecify */
    }

Note that I'm specifying font sizes in pixels (px) to make the math easier. Users who have changed the default font size in their browser preferences probably did so because they want larger or smaller text, and actually using pixel font sizes gets in the way of this.

Anyway, why would you want to use this? Largely because, on the Web, you don't actually know what font is going to be used. Different machines, especially when running different operating systems, have different fonts on them. Even the same font might be used slightly differently on different operating systems. The lowercase letters in different fonts take up a different proportion of the font's size. How big text appears and how much width it takes up is often more closely related to the size of the lowercase letters than the uppercase. More specifically, this can be useful for things like:

I'll give an example of the latter by looking at the Web page I mentioned at the beginning. It wants the proportional and monospace text to be the same size. Currently, it compensates for Firefox's smaller monospace font size preference (incidentally, something I'd like to get rid of in the future using the same infrastructure we use for font-size-adjust) by specifying:

    code { font-size: 1.2em; }

Depending on what my default monospace font is, I get different results:

[SCREENSHOT] [SCREENSHOT]

The first example is probably roughly what the author intended; in the second example the monospace text is clearly too small.

If I add font-size-adjust: 0.6 to the body and change to code { font-size: 1em; }, I end up with the following result:

[SCREENSHOT] [SCREENSHOT]

Here the fonts are consistent, but probably too large, partly since monospace fonts tend to appear bigger because many of the characters are wider. So let's try again, this time with code { font-size: 95% }:

[SCREENSHOT] [SCREENSHOT]

Now the results are roughly the size I think the author intended, and they're consistent between different fonts.

Unfortunately, I'm afraid the monospace font size preference is still interfering with things, so this may not be as useful as it could be.

rgba() and hsla() colors

We now support the rgba() (Red-Green-Blue-Alpha) and hsla() (Hue-Saturation-Lightness-Alpha) color values from css3-color. (I'm actually the new editor of this specification, and a new last call working draft should be out within a few weeks.)

These are in addition to the existing opacity property (which we've supported since Firefox 0.9 or Mozilla 1.7), which can be used to make an element and all of its descendants partially transparent as a single unit. These new color values are different because they specify alpha that is used right when the things with that color are drawn.

I'm sure people who are better at visual design than I am have lots of pretty uses for these, but I'll give some rather plain-looking examples, just to show the difference between compositing the entire element as a unit and doing each drawing operation separately.

For a start, let's look at a div containing a header, with the following styles (see HTML):

    body { background: url(stripes-6); }
    div { background: lime; opacity: 0.5; }
    h2 { background: red; }

[SCREENSHOT]

In this case, where the header is on top of the div, the header's red background completely covers the lime green background of the div, so no green shows through there. But the whole thing (the unit, in which the red completely covers the lime) is drawn at 50% opacity against the body's blue background, so the blue shows through both.

Instead, suppose we do this: (see HTML):

    body { background: url(stripes-6); }
    div { background: rgba(0, 255, 0, 0.5); } /* alpha component in color */
    h2 { background: rgb(255, 0, 0); }

[SCREENSHOT]

In this case, only the green is partially transparent. The red background is fully opaque, as is the text.

Finally, let's look at something a little more complicated (see HTML):

    body { background: url(stripes-6); }
    div { background: rgba(0, 255, 0, 0.5); } /* alpha component in color */
    h2 { background: rgba(255, 0, 0, 0.5); } /* alpha component in color */

[SCREENSHOT]

In this case, both of the backgrounds are partly transparent. But, unlike the first time, they're drawn separately rather than one unit, so the green is visible behind the red, making the background of the heading look brown. The text is still fully opaque.

New values for width, min-width, and max-width

We support four new values for the width, min-width, and max-width properties: -moz-max-content, -moz-min-content, -moz-fit-content, and -moz-available. These values are planned to be part of the css3-box specification.

Like the new values of display that I wrote about above, these are likely to be basic tools that authors find particularly useful in complicated situations. But they do allow a few simple demos as well.

I'll start with a little bit of background: pieces of content have two intrinsic widths that are used in CSS layout engines. In a very simple example, a paragraph containing text (and no line breaks), the larger of these intrinsic widths is the length of the text when laid out all on one line, and the smaller of these intrinsic widths is the width of the longest word in the text. (For more complicated examples, the definitions of these widths are more complicated.)

The values -moz-min-content and -moz-max-content specify those two intrinsic widths. They're not particularly useful on the width property, but they may be more useful on the min-width and max-width properties.

The value -moz-available allows specifying the width that normal blocks (but not floats, tables, or inline-blocks) already have with width: auto: using the width of their container. Again, this probably isn't all that useful for the width property, but it's probably more useful for max-width.

The most useful of these values for the width property is -moz-fit-content, which gives the sizing algorithm used to size tables and floats. This sizing algorithm is pretty simple, actually: it's just the larger of (1) -moz-min-content or (2) the smaller of -moz-max-content or -moz-available.

This value actually does let authors do some things that previously weren't possible without tables, such as putting a backround on headings that doesn't fill the whole width of the container unless the heading does, but is a single rectangle if the heading breaks to multiple lines (see HTML):

[SCREENSHOT]

white-space: pre-wrap

We now support the pre-wrap value of the white-space property. (We'd long supported the -moz-pre-wrap value, but now our implementation has been updated to the CSS 2.1 specification, which introduces pre-wrap, and the value has been renamed.)

This allows displaying preformatted text in a way that wraps when the text doesn't fit in the width of its container. This can be useful for things like source code samples and mailing list archives. For example, if you look at this historic message in the W3C mailing list archive, it looks like this:

[SCREENSHOT]

But if you make the window much narrower, the text still doesn't require horizontal scrolling:

[SCREENSHOT]

Many people contributed to the work involved in adding these new features and the many other new CSS features in Firefox 3. The work in rewriting our graphics architecture was particularly important, and led to a number of these new features (and should lead to more new features in the near future). These contributions include a lot more than just writing code. I'd like to thank everybody who filed bug reports, analyzed bugs and wrote testcases, fixed them, and documented the new features for their contributions to the features that I described above and the architecture work that they depend on, and to getting all of that work into a state that we can be proud of shipping as Firefox 3. I'd particularly like to thank Uri Bernstein, John Daggett, Daniel Holbert, Bernd Mielke, Simon Montagu, Masayuki Nakano, Robert O'Callahan, Mats Palmgren, Stuart Parmenter, Jesse Ruderman, Eric Shepherd, Karl Tomlinson, Ryan VanderMeulen, Vladimir Vukićević, Martijn Wargers, Boris Zbarsky, and the cairo team.

I'd also note that we're already working on new features for the next release, and there are lots of ways to help out, from trying them out and filing useful bug reports, to helping with writing regression tests for new features, to even writing the code to implement them. Come join us!