The other day I had to do some work which involved working with fonts and other styles using Javascript. It involved extracting inline or CSS style values, calculating sizes in pixels and converting various units from em to px or pt to px etc. As with most tasks that should be simple it was a real leason in browser incompatibility and ended up taking far too much of my time. In W3C standard compliant browsers you can use the getComputedStyle function e.g
window.getComputedStyle("someID", "").getPropertyValue("font-size");
This will return the actual size in pixels computed by the browser. So if the element had a style set to 12pt it would return 16px. This is great but like most things in life you can guarantee that IE will do things differently and only half as good. They use a function called currentStyle e.g
document.getElementById("someID").currentStyle["fontSize"];
The first difference is that you refer to the style in CamelCase rather than separated by hyphens as you would in the stylesheet. The second is that the returned value will not be in pixels but will be in the same units as defined in the stylesheet or inline style. Now if you wanted to return the size in pixels like the computedStyle function it means having to do quite a lot of work as you need to convert the unit that currentStyle retuns into px. Obviously I didn't realise quite how much work it would be and after I read a few articles I naively decided to write my own function to correctly compute styles in IE combining all the tasty tit bits I had come across in a nice simple object.
Conversion Problems
Trying to convert certain units to pixels is not so much of a problem and there are different ways to accomplish this. Some conversions like points to pixels are simple math depending on whether or not how accurate you want to be. Others such as percentages or ems have to be done in relation to their parent elements. I came across Dean Edwards runtimeStyle hack which jQuery also uses but it didn't handle percentages accuratley so I looked at the hidden div measurement function where a div is inserted into the DOM with the required style and then measured before removing it again. This seemed to handle most units apart from IE6 in certain cases. With percentages you also have the problem of "auto" which means that the currentStyle value is returned with the same value as the parent and you need to work out whether to calculate the computed value as a percentage of the parent or set it to the same value as the parent.
Other font-size styles such as smaller and larger cannot easily be converted to px as they depend on the browsers current text-size or zoom settings and are also taken in relation to other styles e.g two nested DIVs both with a font-size of larger means that the child DIVs font-size is larger than its parent which in turn is larger than the style it inherits from. For the values xx-small, x-small, small, medium, large x-large and xx-large you can start off with a simple lookup function that takes into consideration whether the browser is IE in quirks mode but then once the user starts changing their browser settings to zoom in or increases or decreases the text-size then these values don't mean jack and as far as I know there is no way to get the current browsers text-size setting to use as a multiplier on the original lookup value.
Fun and Games with IE6
Also least I ever forget there is the joy of IE6 which meant that as soon as I changed the css stylesheet of my article from my blog to this current one it meant that my previously working font-size function suddenly started adding extra units to my previous working values. I tracked down the rule that causes this:
#main {
background: url(http://www.blogblog.com/thisaway_blue/bg_content.gif) repeat-x left top;
}
But have yet to find a reason why it affects the measurement of a hidden div when appended to the DOM so if anyone knows why then let me know. Therefore I have had to add a few IE 6 specific hacks into the function to handle its odd behaviour. Although not perfect and taking into consideration all I have mentioned about certain unit calculations I have run some test cases and it seems to work okay when working with a series of nested DIVs each with different font-style units and values. If there are issues with the code and I am sure there will be then please let me know. Like always with me this started off as a little 10 minute function and ended up as one of those "I will not be beaten" battles that you wish you never started. Only after reading one too many articles do you realise that there is a probably a good reason why no-one has managed to do this properly before. What bugs me the most is why Microsoft when redeveloping their Javascript and rendering engine for IE8 didn't think that it might have been a good idea to include a function to return the correct computed value.
CSSStyle Object Function Results
The following is an example of my object in action. I have created some nested HTML elements with various inline and CSS styles and then when run the function will test each element in turn and output the following to the results container:
- The style.fontSize, style.cssText, currentStyle, runtimeStyle and computedStyle values.
- The value that JQuery's curCSS function returns.
- The value that Dean Edwards hack returns (IE only).
- The value that my CSSStyle getComputedStyle function returns.
- The values that my CSSStyle FontSize function returns.
The values returned should match those that are labeled below in the relevant DIV containers. Also the results from running this in Internet Explorer should roughly match those from running in Firefox, Opera, Chrome, Safari etc. The HTML I am checking the styles for is below:
<div id="d1" style="font-size: small;">
<div id="d2" style="font-size: 12pt;">
<div id="d3" style="font-size: 1.5em;">
<div id="d4" style="font-size: 75%;">
<div id="d5" style="font-size:auto;">
<div id="d6" style="font-size: 0.9em;">DIV 6: Size 0.9em = 16px
<div id="d7" style="font-size:150%">DIV 7: Size 150% = 24px</div>
</div>
</div>
</div>
</div>
</div>
</div>
The following HTML contains the nested DIVs that the function will be looking at.



