BlackWolf
BlackWolf

Reputation: 5629

Getting class-based CSS attribute via JS not working

I have JS code where I try to determine if the size of an image was explicitly set via CSS or the by using the width/height attributes. If so, I respect the set sizes, otherwise I execute code to size the image myself. Here is the code. It uses some jQuery, so image is a jQuery object and image[0] accesses the actual DOM element:

if (image.attr('height') == undefined && image[0].style.height.length == 0) {
    image.data("explicit_height", false);
    //Do stuff to the image size here
} else {
    image.data("explicit_height", true);
}

// ...SAME FOR WIDTH...

The problem I am facing is that this code works fine as long as either the height/width or style attributes are used. When the height/width is set via a CSS selector (for example a class selector), the code is NOT working. The code is executing on window load.

Anyone got an idea why this happening and how to fix it?

Upvotes: 0

Views: 78

Answers (1)

Josh Beam
Josh Beam

Reputation: 19802

You have to use getComputedStyle or currentStyle to get styles set in a stylesheet (the latter works in earlier versions of IE.) style will only return inline style properties.

(image.getAttribute('height') == null
 && ((window.getComputedStyle(image)||image.currentStyle)['height']) == '0px') ?
    //do stuff
:
    //do other stuff

You could also map the evaluation of that statement to an object of functions:

function foo() { image.data("explicit_height", false) }
function bar() { image.data("explicit_height", true) }

var bool = ( image.getAttribute('height') == null
 && ((window.getComputedStyle(image)||image.currentStyle)['height']) == '0px' ),
fn = {
    true:foo,
    false:bar
}[bool]();

You'll need to play around with image.getAttribute('height') == null and the statement that follows that, because they are based on default values in the browser, which could be different (I only tested on Firefox 26 for Mac 10.9, and the default values where there is no height attribute is null and where there is no height declared in a stylesheet is 0px.)

Updated Answer

Check out this jsfiddle:

var image = document.getElementsByTagName('img')[0];

function foo() { image.setAttribute("name", "foo") }
function bar() { image.setAttribute("name", "bar") }

var styleSheets = document.styleSheets;

function isHeightDefinedInStyleSheets(tag) {
    for(i in styleSheets) {
        var rules = styleSheets[i]['cssRules'||'rules'];        
        if(rules!==undefined) {
            for(j in rules) {
                if(rules[j]['style']!==undefined&&rules[j].selectorText===tag) {
                    if(parseInt(rules[j]['style']['height'])>0) {
                        console.log(true);
                         return true;   
                    }
                }
            }
        }
    }

    console.log(false);
    return false;
}

var fn = {
    true:foo,
    false:bar
}[!isHeightDefinedInStyleSheets('img') && image.getAttribute('height') == null]();

This function will check the stylesheets themselves for whether a rule exists (which is different than getComputedStyle, which will get the style of the element based on its computed value, regardless of whether the value was defined inline or in a stylesheet, etc.) Its return value is passed along as a key with the return value checking whether height was defined inline as an attribute to the image. If the statement evaluates "true", it will execute the "true" function (foo) in the object fn; otherwise it will execute bar.

I haven't dealt with the styleSheets property before, so the code needs to be cleaned up quite a bit, but it demonstrates the basic point. Also, if you have a collection of img elements, you'll need to implement a looping function to iterate through each element in the collection.

Upvotes: 1

Related Questions