11 Feb 2009 kr   » (Journeyer)

Implementing the CSS3 “rem” unit in Firefox

For the impatient, here’s the punchline: nightly builds of Firefox (aka Minefield) now support the CSS3 “rem” unit. It’ll also be in Firefox 3.2 (but not 3.1 – it’s too late for that).

The Story

Recently I found myself writing CSS for a grid-system layout. I learned that, to keep a consistent vertical rhythm, you want the actual value of line-height (in device units) to be consistent. If you have elements with different font sizes, they must also specify different values for line-height. (See the link above for a more thorough explanation.) Here’s an example. For reference, I’ve included the size in pixels for most browsers in the default configuration.

  :root {
  font-size: 1em; /* 16px */
  line-height: 1.5em; /* 24px */
}

h1 {
  font-size: 1.5em; /* 24px */
  line-height: 1em; /* 24px */
}

h2 {
  font-size: 1.16667em; /* 18.6667px */
  line-height: 1.286em; /* 24px */
}

em, strong {
  font-size: 1.16667em; /* dangerous! */
  line-height: 1.286em;
}

This is unfortunate because it obscures the relationship between the line heights of the various elements. (They are, in fact, equal.)

Things are further complicated by the behavior of font-size, which serves as the basis for the em unit. The font size of a nested element is inherited from its parent element. A careless font-size declaration will compound upon itself, and can easily result in text (and line height) of unintended size.

Fortunately, CSS3 provides a neat solution to all this, in the form of “rem” units. Just as em is defined relative to the font size of the current element, rem is defined relative to the font size of the root element. This allows you to use an accessible, user-configurable, zoomable unit, while gaining clean, unconfusing, nice round numbers in your CSS rules.

  :root {
  font-size: 1rem; /* 16px */
  line-height: 1.5rem; /* 24px */
}

h1 {
  font-size: 1.5rem; /* 24px */
  line-height: 1.5rem; /* 24px */
}

h2 {
  font-size: 1.16667rem; /* 18.6667px */
  line-height: 1.5rem; /* 24px */
}

em, strong {
  font-size: 1.16667rem; /* safe; 18.6667px */
  line-height: 1.5rem; /* 24px */
}

Unfortunately, no major browser has implemented this unit.

But this isn’t a huge feature, even for someone like me who has no familiarity with the Mozilla codebase. Plus, now that Mozilla is using a decent version control system, I had no excuse. So, rather than just complaining about the situation (as I usually do), I decided to do something about it.

Write a patch

I cloned the Mozilla repository and set about hacking. First I made myself some test cases – small HTML files that used rem in ways that demonstrated its existence and behavior as distinct from em.

Despite being a vast C++ codebase, Mozilla is reasonably well-organized and not too hard to follow, especially once you learn the conventions. Still, getting things to work took a couple of days of sporadic hacking, an hour here and there. Almost all of this time was spent hunting around the code and documentation, looking for the right method to call or variable to pass.

When I was satisfied, I created bug 472195 as a place to post my patch and get feedback. And boy did I. In less than 24 hours, David Baron gave me a very helpful reply listing a bunch of problems with my work, some of which were stylistic and some of which were more serious. He also introduced me to Mozilla’s automated testing frameworks (yes, there are more than one), which I was very happy to see.

After a couple rounds of fixes, the patch was satisfactory and David committed it. You can try it out for yourself in a nightly build. I doubt this will excite many people other than web developers obsessed with both careful typography and scrupulous accessibility (probably a small intersection indeed), but I’m happy to finally be able to use this unit, even if it’ll be some time before I can rely on its availability for a consumer-facing web site.

I’m most curious to see if this spurs any other browsers to implement rem to maintain feature parity.

Syndicated 2009-02-02 08:00:00 from Keith Rarick

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!