Modernizr: Discoveries Made During Development

Two days ago, I launched Modernizr—a small JavaScript toolkit that uses feature detection techniques to determine what CSS3 and HTML5 features the current browser supports—and in doing so I mentioned that I would elaborate on some of the discoveries made while developing the toolkit; discoveries about browsers and their behaviors that certainly opened my eyes in new ways.

For CSS3 properties, the primary method that Modernizr uses to determine support in the browser is by setting the style property in JavaScript with the feature being tested, and then immediately retrieving the style. Ordinarily, if you can retrieve it again it means the browser understood the instruction and implemented it, and then it’ll still have it on the style property for retrieval. If the browser doesn’t understand the instruction, it will disappear into the abyss.

(pause for dramatic effect)

Ahem. This approach is a safe way of doing feature detection, but it unfortunately comes with a couple of caveats. For instance, most of the shorthand properties (border, margin, padding etc.) are not implemented for retrieval in most browsers. Whether they should be or not is debatable, of course, but it’s certainly easy to expect the browser to support it. For reliability purposes, Modernizr avoids shorthands (with one exception I’ll explain below).

Another thing is that browsers lie. A lot. A sample:

  1. Firefox, up until the just-now-released 3.5, has claimed to have text-shadow support built in and will behave like a browser that has it implemented. It does not, however, render any text shadow (until 3.5 which finally does).
  2. Chrome 1.x, which uses WebKit as its engine but has its own graphics engine, claims to support many things but doesn’t actually render them on screen: text-shadow, box-shadow, @font-face fonts, and so forth. The Chrome 2.x series has fortunately caught up in this regard, so let’s hope for quick adoption of it.
  3. Opera merrily reads @font-face settings and claims it understands them, but it does not render them. (Chrome 1.x is the same in that regard)
  4. Internet Explorer (up to and including 8) will accept almost any nonsense you throw at the style property, whether it supports it or not. It is the only browser to do such a thing, fortunately.

Then there are interesting little behaviors that many of you may already be aware of, but I wasn’t. Another list:

  1. Opera, as far as I could tell, does not actually make use of their own -o- prefix for any of the features Modernizr tests against. On the plus side, it means I had to ensure I wouldn’t forget to testfor non-prefixed versions of all the CSS properties as well. On the downside, it kind of defeats the purpose of the prefixes. Opera eventually said that they planned on implementing CSS3 Borders and Backgrounds in version 10 of their browser without vendor prefix, but as appealing as that may sound to some, it puts the onus entirely on them for all of the testing. Personally, I don’t think that’s a good idea.
  2. Mozilla uses a capital M for its DOM property names for experimental properties, e.g. MozBorderImage, which goes against typical DOM conventions. WebKit, curiously, allows for the capital W as well the lowercase w, but does not support the capital K even though the formal name is WebKit. Their own behavior follows the standard, though: webkitBorderImage.
  3. WebKit has proposed the CSS Masks specification, but this turns out to overlap with the (existing) CSS SVG Masks spec. The W3C also has not (yet?) formalized CSS Masks and I don’t expect it to at this point.
  4. While the W3C has not adopted the Webkit team’s CSS Gradients proposal, I’ve included it as a part of Modernizr nonetheless. The simple reason is that CSS Gradients are quite possibly the coolest, most powerful and most useful new development in the world of CSS in the past 5 years. Along with CSS Transitions, which has become an official CSS3 Module.

Translations

Browsers accept multiple formats for certain properties—like how you can write a HEX color value as both #FFF and #FFFFFF, as well as with the English word “white”—and in testing against newer values in CSS3, I unearthed some more of this behavior.

For example, both Mozilla and WebKit support the rgba() and hsla() color inputs, which are simply colors with an alpha channel. However, when you specify something in hsla(), it will be internally translated to its respective rgba() values. WebKit also translates all regular (non-alpha) color values to their rgb() equivalent, which Mozilla does not. Opera, on the other hand, translates every color to its HEX value, which they’ll obviously need to change to support rgba().

WebKit’s CSS Transforms are all translated into their respective matrix() values in the DOM. This is a useful way to get more familiar with matrix translations, if that’s your thing. Similarly, the CSS Transition Timing Functions (ease, ease-in, ease-out, etc.) are all translated to their respective cubic-bezier() curve values.

Multiple backgrounds

One of the biggest challenges turned out to do accurate detection for multiple background support. An absolute, non-permissible requirement for Modernizr was that it only used standards-compliant detection methods, no hacky workarounds or anything like that.

Unfortunately, as mentioned above, Internet Explorer tends to just accept any bogus input for a real CSS property and returns it as-is. This can be problematic in a variety of ways, but for multiple backgrounds it meant I had to figure out a workaround that was still completely standards-compliant.

What I ended up discovering is that IE will not just regurgitate your input if you do this:

background: url(foo.png), url(foo.png), #000 url(foo.png);

The key being the small hex color setting, which the spec dictates can only be set once, as part of the last background layer declaration. None of the browsers that don’t support multiple backgrounds correctly, IE included, understand what to do with this input and as a result, it meant that I could accurately use the output as a way to detect multiple backgrounds support.

Interestingly, it ended up being a shorthand property that solved this problem.

Incomplete testing and support

As Modernizr.com already explains with footnotes, the CSS Columns and CANVAS tests are very rudimentary at this stage. One problem is that some browsers (or versions of browsers) have certain features implemented, but don’t expose their API yet.

An example is Safari 3.2.1 and window.CanvasRenderingContext2D, which works if you use it but the API claims it doesn’t exist. Things like that make those tests a little less reliable, but for the 1.0 release I plan to do more thorough testing and, perhaps, offer a setting for outputting “partial-canvas” as a classname if only parts of the spec are implemented.

All things considered, Modernizr was as exciting to work on for the functionality it would offer people in building much more amazing websites, as it was to discover all these things about the ways browsers work (or break, as it may). And this is only the start: I can’t wait to see what kind of strange behaviors we’ll uncover as we start using Modernizr to progressively enhance our sites and start taking advantage of these fantastic CSS3 features.

If you liked this, you should follow me on Twitter!