Can jQuery get all CSS styles associated with an element?
Asked Answered
A

5

308

Is there a way in jQuery to get all CSS from an existing element and apply it to another without listing them all?

I know it would work if they were a style attribute with attr(), but all of my styles are in an external style sheet.

Amaro answered 16/4, 2009 at 3:8 Comment(0)
H
345

A couple years late, but here is a solution that retrieves both inline styling and external styling:

function css(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 = {};
    if (!css) return s;
    if (css instanceof CSSStyleDeclaration) {
        for (var i in css) {
            if ((css[i]).toLowerCase) {
                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;
}

Pass a jQuery object into css() and it will return an object, which you can then plug back into jQuery's $().css(), ex:

var style = css($("#elementToGetAllCSS"));
$("#elementToPutStyleInto").css(style);

:)

Hypnology answered 29/4, 2011 at 9:46 Comment(28)
BTW, when you say a JSON object, you just mean a JavaScript object right?Amaro
+1 Mark, great solution which i've just given credit to in this answer :)Sumrall
this looks awesome, but when I'm trying it it misses out on certain properties such as font-family.Examination
@Examination any clue why? Is it a per-browser issue?Hypnology
It's fine actually. I was erroneously expecting inline styles to come with it.Examination
@Damon: That's a valid assumption, considering the first line of the answer says ...here is a solution that retrieves both inline styling and external styling.Amaro
@Examination it does not miss out on certain properties, inline or not. I just checked on it myself. Could you please provide jsfiddle or gist showing that it does not work? Elsewise it worked just fine.Hypnology
My bad. When I said inline I was really talking about inherited stylesExamination
One problem with otherwise great solution is some browsers apply Same Origin Policy and will set cssRules to null.Amaro
+1, but it seems vulnerable to clobbering styles with higher precedence if they're in the wrong order in a stylesheet. Solving that may be quite complex and probably expensive.Wagoner
Just tried using the code, it seemed to trip up giving me this error in chrome: Uncaught Error: Syntax error, unrecognized expression: button.ui-button::-moz-focus-innerJenson
"button.ui" does not appear anywhere in this code, so I'm not sure how it could have a syntax error on that? Are you sure it isn't a browser plugin? I can't get the error to happen. Have a JSFiddle?Hypnology
This code doesn't work any more (always returns empty object in Chrome)Dunghill
Providing a patch/fix or jsFiddle that highlights exactly where your error is happening (if any) would be greatly appreciated - to back up your claim and provide insight for others. Thanks!Hypnology
Note: getMatchedCSSRules is currently only implemented in Webkit browsers ( Compatibility Table ), so using this in Firefox or IE will cause problems. You'll need a polyfill to handle this code.Gutturalize
Note: Moderators have modified my original code, I give no guarantee anything will work.Hypnology
does this also get css for all descendant elements?Hillary
Note, this does not retrieve the browser default styles, only styles that have been applied by stylesheets or inline.Cheshvan
Not working for me , I tested in chrome console. it is not working. When i put "var style = css(jQuery('#main input'));" after executing the css() function, i got following error "Uncaught Syntax error, unrecognized expression: hover "Selftaught
CORS is starting to piss me off with all it's retardedness: You'll get a Error: The operation is insecure. if the CSS is from remote site...Evetteevey
here is a fiddle of my version, which is quite similar, but doesn't choke on psuedo-selectors. also has a demo: jsfiddle.net/a2f0phg5/1Mansion
I found this solution craps out if you use @import, any way around that, other than of course not using @import?Faucal
This won't work for HTTPS sites in Chrome due to security policyCountenance
Joining @Cheshvan I want to remind that the solutions above do not copy the hover, active etc. states of the selected items. :-/Boehm
@Boehm I haven't tried it, but if you need the :hover states you could trigger a mouseover. Not sure if you could get active. Maybe triggering a mousedown? Give it a try.Cheshvan
This code now causes Error: The operation is insecure on firefox (chrome still works). This is due to .cssRules in var rules = sheets[i].rules || sheets[i].cssRules;. You will need try/catch around this line to protect for Firefox.Hypesthesia
Also in firefox I get: "Error: Syntax error, unrecognized expression: unsupported pseudo: hover" Does it take in consideration pseudo classes?Unpeople
Facing Uncaught DOMException: Failed to read the 'rules' property from 'CSSStyleSheet': Cannot access rules , what is the issue ?Genipap
E
92

Two years late, but I have the solution you're looking for. Not intending to take credit form the original author, here's a plugin which I found works exceptionally well for what you need, but gets all possible styles in all browsers, even IE.

Warning: This code generates a lot of output, and should be used sparingly. It not only copies all standard CSS properties, but also all vendor CSS properties for that browser.

jquery.getStyleObject.js:

/*
 * getStyleObject Plugin for jQuery JavaScript Library
 * From: http://upshots.org/?p=112
 */

(function($){
    $.fn.getStyleObject = function(){
        var dom = this.get(0);
        var style;
        var returns = {};
        if(window.getComputedStyle){
            var camelize = function(a,b){
                return b.toUpperCase();
            };
            style = window.getComputedStyle(dom, null);
            for(var i = 0, l = style.length; i < l; i++){
                var prop = style[i];
                var camel = prop.replace(/\-([a-z])/g, camelize);
                var val = style.getPropertyValue(prop);
                returns[camel] = val;
            };
            return returns;
        };
        if(style = dom.currentStyle){
            for(var prop in style){
                returns[prop] = style[prop];
            };
            return returns;
        };
        return this.css();
    }
})(jQuery);

Basic usage is pretty simple, but he's written a function for that as well:

$.fn.copyCSS = function(source){
  var styles = $(source).getStyleObject();
  this.css(styles);
}
Erickson answered 20/6, 2011 at 19:41 Comment(6)
@Damon: Thanks! I've updated my post, and edited the wording slightly to make it clear that this is not my work. Sorry about the previous wording, I think I typed this answer up late at night, but either way, it was pretty douchey.Erickson
Why does this return this.css()? There's no documentation for this method taking no arguments, and if this statement is reached, it throws an exception. I think it would be more appropriate to return returns; even if it's an empty object.Presser
Would it be possible to get a working demo of this? Not clear to me where to put this code and how to invoke it. It's also not clear to me where the output is being stored. Thanks.Thuja
I do not understand how to use it, There's something called jsfiddle that most people use to help. Good programmer are the worse teacherAcaulescent
@Acaulescent If you want to copy the style of div1 to div 2 just use: $("#div2").copyCSS($("#div1")); and to get the style of any element you could use: JSON.stringify($('#element').getStyleObject());Deepen
@Thuja If you want to copy the style of div1 to div 2 just use: $("#div2").copyCSS($("#div1")); and to get the style of any element you could use: JSON.stringify($('#element').getStyleObject());Deepen
V
18

Why not use .style of the DOM element? It's an object which contains members such as width and backgroundColor.

Voltaism answered 16/4, 2009 at 3:25 Comment(3)
I'm pretty sure this is the only way to get the actual styles associated with the class. (as opposed to the calculated styles which are different)Majors
With .style you only get properties applied to the style attribute of the element, but not those applied with a CSS class.Luminary
+1 as i m using inline script and changing it dynamically afterwordsUntruth
S
11

I had tried many different solutions. This was the only one that worked for me in that it was able to pick up on styles applied at class level and at style as directly attributed on the element. So a font set at css file level and one as a style attribute; it returned the correct font.

It is simple! (Sorry, can't find where I originally found it)

//-- html object
var element = htmlObject; //e.g document.getElementById
//-- or jquery object
var element = htmlObject[0]; //e.g $(selector)

var stylearray = document.defaultView.getComputedStyle(element, null);
var font = stylearray["font-family"]

Alternatively you can list all the style by cycling through the array

for (var key in stylearray) {
console.log(key + ': ' + stylearray[key];
}
Seessel answered 24/9, 2014 at 9:11 Comment(1)
D
4

@marknadal's solution wasn't grabbing hyphenated properties for me (e.g. max-width), but changing the first for loop in css2json() made it work, and I suspect performs fewer iterations:

for (var i = 0; i < css.length; i += 1) {
    s[css[i]] = css.getPropertyValue(css[i]);
}

Loops via length rather than in, retrieves via getPropertyValue() rather than toLowerCase().

Doubleminded answered 16/12, 2013 at 21:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.