EniGma
EniGma

Reputation: 2464

document styleSheets get all styles on an element with pseudo-selector

According to this answer, I get all the element styles,

home.html

<div id="divClass" class="myclass">Text Here</div>

style.css

#divClass{    
   color:red; 
   background-color:black;
   float:left;
} 

script.js

  function copyComputedStyle(a) {
    var sheets = document.styleSheets,
      o = {};
    for (var i in sheets) {
      var rules = sheets[i].rules || sheets[i].cssRules;
      for (var r in rules) {
        if (a.is(rules[r].selectorText)) {
          o = $.extend(o, css2json(rules[r].style), css2json(a.attr('style')));
        }
      }
    }
    return o;
  }

  function css2json(css) {
    var s = {};
    var pattern = /^[1-9][0-9]?$|^100$/;
    if (!css) return s;
    if (css instanceof CSSStyleDeclaration) {
      for (var i in css) {
        if (css[i].toLowerCase) {
          // Some of the key value pairs were vice versa, so try to make them in order!
          // Ex:    0:flex-grow;  0:flex-shrink;  --------> flex-grow: 0; flex-shrink: 0;
          // End
          if (pattern.test(css[i])) {
            s[css[css[i]].toLowerCase()] = css[i];
          } else {
            s[css[i].toLowerCase()] = css[css[i]];
          }
        }
      }
    } else if (typeof css == 'string') {
      css = css.split('; ');
      for (var i in css) {
        var l = css[i].split(': ');
        s[l[0].toLowerCase()] = l[1];
      }
    }
    return s;
  }

console.log(copyComputedStyle($("#divClass")));

it returns an Object

{
   background-color: "black",
   color: "red",
   float: "left",
   left: ""
}

Now, when I add any pseudo-selector hover or before and after to this div, the copyComputedStyle does not log the added styles and return the same style as before!

#divClass{    
   color:red; 
   background-color:black;
   float:left;
}
#divClass:hover{    
   color:blue; 
} 

How can I overcome that?

Upvotes: 0

Views: 329

Answers (1)

Juli&#225;n
Juli&#225;n

Reputation: 1396

The problem is when using .is(), especially when #divClass is not matching to #divClass: hover

One solution is to use indexOf to make sure you find the selector that matches the element ID:

Change this: if (a.is(rules[r].selectorText)) {

for this: if (rules[r].selectorText && rules[r].selectorText.indexOf(a.attr('id')) != -1) {

If you change that line in your code it will return something like this:

{
   background-color: "black",
   color: "blue",
   float: "left",
   left: ""
}

It is because there are duplicate color properties in the object and the latter predominates, personally what I would do is have an object with the styles per selector grouped:

 function copyComputedStyle(a) {
    var sheets = document.styleSheets,
        o = {},
        objrules = [];

    for (var i in sheets) {
      var rules = sheets[i].rules || sheets[i].cssRules;
      
      for (var r in rules) {
        if (rules[r].selectorText && rules[r].selectorText.indexOf(a.attr('id')) != -1) {
          o = $.extend({},css2json(rules[r].style));
          objrules.push({'selector' : [rules[r].selectorText], 'style' : o});
        }
      }
    }

    return objrules;
  }

  function css2json(css) {
    var s = {};
    var pattern = /^[1-9][0-9]?$|^100$/;

    if (!css) return s;

    if (css instanceof CSSStyleDeclaration) {
      for (var i in css) {
        if (css[i].toLowerCase) {
          // Some of the key value pairs were vice versa, so try to make them in order!
          // Ex:    0:flex-grow;  0:flex-shrink;  --------> flex-grow: 0; flex-shrink: 0;
          // End
          if (pattern.test(css[i])) {
            s[css[css[i]].toLowerCase()] = css[i];
          } else {
            s[css[i].toLowerCase()] = css[css[i]];
          }
        }
      }
    } else if (typeof css == 'string') {
      css = css.split('; ');
      for (var i in css) {
        var l = css[i].split(': ');
        s[l[0].toLowerCase()] = l[1];
      }
    }
    
    return s;
  }

console.log(copyComputedStyle($("#divClass")));

Upvotes: 1

Related Questions