2

I've got a simple input field as follows:

<input type="text" name="search_location" id="search_location" placeholder="Any Location" autocomplete="off">

Using jQuery, I'm trying to get all styles associated with it. The code for this looks like this (got it from this stackoverflow thread):

// Get all styles associated with element
var style = css(jQuery("#elementToGetAllCSS"));

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;
}

// Apply styles to target element
var style = css(jQuery("#elementToGetAllCSS"));
jQuery("#search_location").css(style);

Everything is peachy, except when it comes to CSS pseudo selectors like :before and :after at which point I get an "unrecognized expression" console error.

Any ideas?

EDIT - My Solution

The answer below will work, although I'm a bit concerned about how future proof the answer will be. With that in mind, there's an alternative that seems to be working fine:

$.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();
    }

var styles = $('elementToGetAllCSS').getStyleObject();
  this.css('search_location);
9
  • 9
    pseudo elements only exists in CSS, you can't access them with javascript directly. Commented Jan 8, 2014 at 21:48
  • Not sure if this will help, but when I have a javascript selector issue I check my cheat sheet at this website. I realize this doesnt answer your question but might help. tutorialspoint.com/jquery/jquery-selectors.htm Commented Jan 8, 2014 at 21:50
  • @Adeneo Any idea on how to bypass the pseudo elements in the code above? Commented Jan 8, 2014 at 21:51
  • @Cam - it's not so much a jQuery selector issue, as it is a CSS selector issue :) Commented Jan 8, 2014 at 21:52
  • have you tried $(this).is(':after'); just shooting in the dark here, not really understanding the issue. I guess you are trying to get all the values for it. Commented Jan 8, 2014 at 21:54

1 Answer 1

2

You can filter out the pseudo selectors in the loop by checking if the selector contains ::

for (var r in rules) {
    if (typeof rules[r] == 'object' && 
        'selectorText' in rules[r] && 
        rules[r].selectorText.indexOf('::') == -1 &&
        rules[r].selectorText.indexOf(':hover') == -1
    ) {
        if (a.is(rules[r].selectorText)) {
           o = $.extend(o, css2json(rules[r].style), css2json(a.attr('style')));
        }
    }
}

FIDDLE

Sign up to request clarification or add additional context in comments.

3 Comments

thanks for the code; Just tried it and it's now throwing errors on :hover instead of :after or :before
:hover, :active etc doesn't get the double ::, so we have to filter for that as well, but it's the same principle, updated the answer
Yep, that'll do the trick. I'm a bit concerned about how future-proof it'll be as there's new pseudo selectors coming into play all the time. I've since managed to figure something out that I believe will be a tad more future proof and have updated the original question :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.