36

Is it possible to detect the computed font-size of a DOM element, taking into consideration generic settings made elsewhere (In the body tag for example), inherited values, and so on?

A framework-independent approach would be nice, as I'm working on a script that should work standalone, but that is not a requirement of course.

Background: I'm trying to tweak CKEditor's font selector plugin (source here) so that it always shows the font size of the current cursor position (as opposed to only when within a span that has an explicit font-size set, which is the current behaviour).

Pekka
  • 442,112
  • 142
  • 972
  • 1,088

3 Answers3

59

You could try to use the non-standard IE element.currentStyle property, otherwise you can look for the DOM Level 2 standard getComputedStyle method if available :

function getStyle(el,styleProp) {
  var camelize = function (str) {
    return str.replace(/\-(\w)/g, function(str, letter){
      return letter.toUpperCase();
    });
  };

  if (el.currentStyle) {
    return el.currentStyle[camelize(styleProp)];
  } else if (document.defaultView && document.defaultView.getComputedStyle) {
    return document.defaultView.getComputedStyle(el,null)
                               .getPropertyValue(styleProp);
  } else {
    return el.style[camelize(styleProp)]; 
  }
}

Usage:

var element = document.getElementById('elementId');
getStyle(element, 'font-size');

More info:

Edit: Thanks to @Crescent Fresh, @kangax and @Pekka for the comments.

Changes:

  • Added camelize function, since properties containing hypens, like font-size, must be accessed as camelCase (eg.: fontSize) on the currentStyle IE object.
  • Checking the existence of document.defaultView before accessing getComputedStyle.
  • Added last case, when el.currentStyle and getComputedStyle are not available, get the inline CSS property via element.style.
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • This looks great, will try it out. – Pekka Dec 23 '09 at 20:42
  • 6
    Be careful, `currentStyle` and `getComputedStyle` are fundamentally different: http://erik.eae.net/archives/2007/07/27/18.54.15/ `getComputedStyle` is incapable of getting the *inherited* style, and always *computes* it as `px`, whether the value was declared as `px` or not. – Crescent Fresh Dec 23 '09 at 21:02
  • Thanks for the caveat. Very good to know. For the job at hand it's fine, as stated above. – Pekka Dec 23 '09 at 21:10
  • 6
    It's actually `document.defaultView.getComputedStyle`, not `window.getComputedStyle` (MDC gets it wrong, or considers its own — Mozilla — implementation only). `getComputedStyle` is specified to be a member of `AbstractView`, which `document.defaultView` implements, and there's really no guarantee that `window == document.defaultView` (neither in specs, nor in practice; in fact, Safari 2.x is a good example of `window != document.defaultView`). It's interesting that PPK does similar mistake in getstyles article that you linked to (testing `defaultView` on `window`). – kangax Dec 23 '09 at 21:46
  • Thanks a lot for your help folks. I got it working with Firefox but am stuck with IE. If you'd like to take a look: http://stackoverflow.com/questions/1956573/runtimestyle-in-ie7-8 – Pekka Dec 24 '09 at 03:55
  • 2
    Sorted. @CMS, if I'm not mistaken you need to edit your answer to point out that `currentStyle` will accept camelized properties only (e.g. fontSize) while `getPropertyValue` works with the original form (font-size). – Pekka Dec 24 '09 at 04:13
  • Many thanks for the feedback guys, edited to check `document.defaultView` instead of `window` as @kangax points out, also added a `camelize` function to get the right properties when working with `el.currentStyle`, any further feedback is really appreciated! – Christian C. Salvadó Dec 24 '09 at 07:01
  • Well, it would also be a good idea to check existence of `document.defaultView` before accessing `getComputedStyle` on it. – kangax Dec 24 '09 at 13:51
  • Does someone know why this doesn't work with jQuery ? if I replace var element = document.getElementById('elementId'); getStyle(element, 'font-size'); by getStyle($('#elementId'), 'font-size') there is a javascript error... – Vinze Jul 06 '10 at 13:12
  • @Vinze: that's because `$('#elementId')` returns a jQuery object while CMS's `getStyle` function expects a DOM element. Use `getStyle($('#elementId')[0], 'font-size')` instead. – Tim Down Oct 06 '10 at 23:25
4

Looks like jQuery (1.9 at least) uses getComputedStyle() or currentStyle itself when you use $('#element')[.css][1]('fontSize'), so you really shouldn't have to bother with more complicated solutions if you're OK using jQuery.

Tested in IE 7-10, FF and Chrome

Tom Auger
  • 19,421
  • 22
  • 81
  • 104
2

To overcome the 'em' problem I have quickly written a function, if the font-size in ie is 'em' the function calculates with the body font-size.

        function getFontSize(element){
        var size = computedStyle(element, 'font-size');
        if(size.indexOf('em') > -1){
            var defFont = computedStyle(document.body, 'font-size');
            if(defFont.indexOf('pt') > -1){
                defFont = Math.round(parseInt(defFont)*96/72);
            }else{
                defFont = parseInt(defFont);
            }
            size = Math.round(defFont * parseFloat(size));
        } 
        else if(size.indexOf('pt') > -1){
            size = Math.round(parseInt(size)*96/72)
        }
        return parseInt(size);
    }

    function computedStyle(element, property){
        var s = false;
        if(element.currentStyle){
            var p = property.split('-');
            var str = new String('');
            for(i in p){
                str += (i > 0)?(p[i].substr(0, 1).toUpperCase() + p[i].substr(1)):p[i];
            }
            s = element.currentStyle[str];
        }else if(window.getComputedStyle){
            s = window.getComputedStyle(element, null).getPropertyValue(property);
        }
        return s;
    }