Browser Rendering – Getting Computed Style is Hard

Recently I was looking into how libraries like jQuery get the compute style of an element. I found that in its simplest form, getting computed style is one step:

function getStyle(el, prop) {
return el.currentStyle ?
el.currentStyle[prop] : // IE
document.defaultView.getComputedStyle(el, "")[prop];
}

IE stores computed properties on the element’s `currentStyle` and the other browsers use the method `document.defaultView.getComputedStyle`. But there are two things that make a robust implementation difficult: (1) shorthand properties don’t work and (2) each browser returns different values. What I mean by shorthand properties are things like border which is made up of border-top-width, border-top-style, border-top-color, border-right-width, border-right-style, border-right-color, etc. Calling `getStyle(el, ‘border’)` returns undefined; you have to call ‘borderTopWidth’, ‘borderTopStyle’, and ‘borderTopColor’ and the other 9 properties for the other 3 sides. This is understandable but may not be intuitive when the css declares the border shorthand property.

And then each browser returns different things. Here are some observations of Firefox 5, Webkit (Chrome 13 and Safari 5.1), and IE8 based on my handful of tests on Windows 7.

  • If given units in em, Webkit and Firefox convert to px, but IE8 will leave as em. So an implementation that computes the width of a 30em-wide element, for example, will have to convert em to px for IE8. Note also that Firefox will return fractions of px for any property.
  • When given a color by name or by hex notation, Webkit and Firefox both convert to rgb while IE8 will keep the given value. So a robust implementation must be able to convert “yellow” to “rbg(255,255,0)”, for example.
  • When using the default font, Firefox returns “serif”, Webkit returns “‘Times New Roman'” with the apostrophes and IE8 returns “Times New Roman” without quotes.
  • Firefox calculated a font size of 0.9em to be 14.4px, Webkit 14px, and IE8 keeps 0.9em. jQuery returns 14px in all cases with its `css` method.
  • All browsers normalize a mixed-case values like `DOTted` to the lowercase `dotted`.

One rendering difference too with a thick dotted border. IE8 renders the dots as circles and spaces them evenly so that there will be no partial circles. Firefox also renders dots as circles but keeps them a fixed distance apart so that the corners usually have artifacts. Webkit renders the dots as squares and, like firefox, overlaps dots in the corners. IE8 renders the background color behind the border and the other browsers do not.

The following CSS renders like the picture below with Firefox 5 on the left, Chrome 13 in the center and IE8 on the right.

#subject {
width: 16em;
height: 17.75em;
border: 1em DOTted #ddd;
background-color: YELlow;
font-size: 0.9em;
line-height: 135%;
}

Browser Comparisons

Also see my JsFiddle version if you want to play around and maybe try other properties. It also shows the results of jQuery’s `css` method.