2

For example I might have some css stuff that looks like this:

.divType1 {
    position: absolute;
    width: 60px; height: 60px;
    left: 400px; top: 100px;
    border: 1px solid #89B;
    z-index: 0;
 }

Now within Javascript I want to gather div class divType1' css attributes, but am provided only with the div class, so I can't do something of form ( pseudo-code ):

selectDivWithClass( divType1 ).getCss(left). 

I could hack something by instantiating a div with class divType1 and grab its css attributes, and then destroy it, but is there a better way?


The original question has some ambiguity, resulting in lots of good answers that will work in other settings. So here's the restated one:

Using Javascript, how do I gather a subset of a div class' css attributes specified by the maker in the stylesheet, so no browser defaults. Furthermore, assume only 'plain-vanilla' attributes will appear in the css. So stuff like width, height, not stuff like:

transition: width 2s;
-moz-transition: width 2s; /* Firefox 4 */
-webkit-transition: width 2s; /* Safari and Chrome */
-o-transition: width 2s; /* Opera */

I am given nothing but the class name, so I am not given a list of attributes I need to collect before hand.

Finally, the function ideally should return an object mapping style attribute to value.

In the scope of what I am trying to do, the problem is solved by @RobG's answer below.

xiaolingxiao
  • 4,793
  • 5
  • 41
  • 88
  • 1
    http://stackoverflow.com/questions/9180184/access-css-file-contents-via-javascript That might give you some insight, shows how to read the contents of the CSS file. – Rick Calder Nov 11 '12 at 22:37
  • Thanks a lot! That's actually awesome and points in the direction I was looking to go, even though now I am more open to the doc frag idea after everyone else said it's not soo bad – xiaolingxiao Nov 11 '12 at 23:01

5 Answers5

3

You could iterate through document.styleSheets, but that many not necessarily be faster than instantiating a DocumentFragment with that class and getting its attributes:

var stylesheets = document.styleSheets;
for (var i=0; i < stylesheets.length; i++) {
    var rules = stylesheets[i].cssRules || stylesheets[i].rules;
    for (var j=0, rule; rule = rules[j++]; ) {
        if (rule.selectorText === '.divType1') {
            alert(rule.style.left)
        }
    }
}

Fiddle: http://jsfiddle.net/dandv/VnCMR/1/

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 1
    Note that in some browsers, `stylesheets[i].rules` will be undefined, you must go via `stylesheet.cssRules`. So you must use feature detection and use the supported property for the UA that the code is running in. – RobG Nov 12 '12 at 00:08
  • Note also that `rule.style` returns the entire style object, it doesn't isolate the style properties for that particular rule, you need to use `rule.cssText` for that. – RobG Nov 12 '12 at 01:01
  • `rule.cssText` has the entire declaration: `".divType1 { position: absolute; width: 60px; height: 60px; left: 400px; top: 100px; border: 1px solid rgb(136, 153, 187); z-index: 0; }"`. `rule.style.left` returns exactly "400px". – Dan Dascalescu Nov 12 '12 at 05:15
  • 1
    The OP seems to want to get all the properties set by a particular rule. The style object has about 250 properties, it's difficult to weed out just the ones for style properties set by the rule. – RobG Nov 12 '12 at 05:50
1

You could add it to a div and then check the details? This works well in jQuery, unfortunately the javascript equivalent doesn't include the class based styles in the style object. So:

var d = $("<div>").addClass("divType1");
console.log(d.css("left"));

would work in jQuery. This in JS wont:

var d = document.createElement("div");
d.className = "divType1";
console.log(d.style.left);
jamie-wilson
  • 1,925
  • 21
  • 38
  • 1
    Read OP's final paragraph: *"I could hack something by instantiating a div with class divType1 and grab its css attributes, and then destroy it, but is there a better way?"* Furthermore, the OP said nothing about jQuery (and neither did you, despite using it in your answer). jQuery-based answers to non jQuery-based questions are not useful (even when they mention it). – T.J. Crowder Nov 11 '12 at 22:34
  • Sorry about the jQuery response, it's automatic unfortunately these days. The final paragraph was added after I answered. – jamie-wilson Nov 11 '12 at 22:41
  • 2
    Yeah sorry guys I added the doc fragment idea literally a minute after I posted the original question, so the confusion is my fault. And jquery or no jquery, I just appreciate the help in general :) – xiaolingxiao Nov 11 '12 at 22:46
  • @user1128571: Well said. Short version is both of the answers you received early on are probably pointing you the right way (actually all three as of this writing), instantiating the element and querying its computed style would be the way to go. That's a bit of a pain without a library, less of a pain with one. – T.J. Crowder Nov 11 '12 at 22:48
  • @jamie-wilson: What in heaven's name is `d.classList`?! And yes, querying the `div`'s `style` property won't give you anything useful, because you haven't set the `style` property, the style is inherited from the `class` (or at least it would be if you set `className`). – T.J. Crowder Nov 11 '12 at 22:49
  • classList is just a short hand way of adding the string to the class attribute. https://developer.mozilla.org/en-US/docs/DOM/element.classList - though on second look, it's not that well supported :/ The downside of only targeting certain browsers! – jamie-wilson Nov 11 '12 at 22:52
  • @jamie-wilson: Yeah, best to stick to standards (er, and even then, just the well-supported bits) when you're giving other people advice. Or at least flag up the things you're relying on. In this case, there's exactly **no** reason to use `classList` rather than the universally-supported `className`. – T.J. Crowder Nov 11 '12 at 22:54
1

You easily come into cross browser hell here.

What works (at least in chrome) IF you have an existing element (which can be created using document fragment as already mentioned) is

var el = document.getElementsByClassName("divType1")[0];
alert(window.getComputedStyle(el).getPropertyValue("left"));

But looking at this you might opt for using a javascript library like jQuery here.

David Müller
  • 5,291
  • 2
  • 29
  • 33
  • That only works if the class is the only rule affecting the element and any default formatting is accounted for (e.g. P elements usually have top and bottom margin, IMG elements may have a border). – RobG Nov 11 '12 at 23:56
1

This gives you all text in first stylesheet

document.styleSheets[0].ownerNode.innerHTML

While this function accepts a selector string and should return its text value

function getStyleBySelector(selector) {
    var sheets = document.styleSheets;
    var selectorRule = false;

    for(var x = 0; x < sheets.length; x++) {
        var rules = sheets[x].cssRules;
        for(var y = 0; y < rules.length; y++) {
            if(rules[y].selectorText == selector) {
                selectorRule = rules[y]
                break;
            }
        }

        if(selectorRule) {
            break;
        }
    }

    var styling = {};

    if(selectorRule) {
        return selectorRule.cssText
    }

    return styling;
}

In your case call it with

getStyleBySelector(".divType1");
lostsource
  • 21,070
  • 8
  • 66
  • 88
1

Inpsecting an element that has the rule applied to it won't work unless you can filter out the effects of all other rules and default properties (which might be different in different browsers and be the same as a rule property in some but not others). That seems unlikely to be successful in more than one or two browsers in their default configurations.

To get the CSS rule text as text in a cross-browser fashion, use something like:

function getCssRule(selector) {
  var sheets = document.styleSheets;
  var rulesObj, rules, ruleText;

  if (sheets.length) {

    // Determine the name of the rules object
    rulesObj = typeof sheets[0].cssRules != 'undefined'? 'cssRules' : 'rules';

    for (var i=0, iLen=sheets.length; i<iLen; i++) {
      rules = sheets[i][rulesObj];

      for (var j=0, jLen=rules.length; j<jLen; j++) {
        if (rules[j].selectorText.indexOf(selector) > -1) {
          return rules[j].cssText;
        }
      }
    }
  }
}

Note that this will return the actual text of the rule.

Also, there is a CSSValue property, but I am unsure of support.

Edit

If you are dealing only with the rules part and not the selector, you should be able to turn it into an object using something like:

function cssTextToObj(cssText) {

  // Trim selector, initial { and closing } plus whitespace, split on ';'
  var props = cssText.replace(/^[^{]+{\s*/,'').replace(/\s*}\s*$/,'').split(';');
  var resultObj = {};
  var bits;

  for (var i=0, iLen=props.length; i<iLen; i++) {

    // Split each property assignment on ':' only where
    // props[i] has a value
    if (props[i] != '') {
      bits = props[i].split(':');
      resultObj[bits[0]] = bits[1];
    }
  }
  return resultObj;
}

You may want to trim the property names and values of leading and trailing spaces, but that should work. I'm no expert on CSS properties though, so the above may need some tweaking.

Note that if there is a trailing ';' (which browsers seem to add if the original rule didn't have one), the last member of props will be '' (empty string).

One thing you absolutely can't guarantee is the order that properties will be in, not that you can know what order for..in will return them in anyway. IE seems to return cssText in its own order, Firefox seems to preserve the original order.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
RobG
  • 142,382
  • 31
  • 172
  • 209
  • This code actually got exactly what I was looking for, it's too bad that it looks like an object...but is in string form, which I cannot use unless it's parsed ( unfair added constraint since I did not specify in the question that I am looking for some sort of hash ) . Quick research turned up the following post about a cssText parser: http://stackoverflow.com/questions/8987550/convert-css-text-to-javascript-object, which seem to suggest that I am going down a dead end... – xiaolingxiao Nov 12 '12 at 00:42
  • Just saw the edit and the newly added parser, I test it on the set of of css attributes that I might encounter ( plain vanilla ones, so nothing like -webkit-transition: blah ) so thanks for the big help! – xiaolingxiao Nov 13 '12 at 01:52