Get a CSS value from external style sheet with Javascript/jQuery
Asked Answered
M

5

65

Is it possible to get a value from the external CSS of a page if the element that the style refers to has not been generated yet? (the element is to be generated dynamically).

The jQuery method I've seen is $('element').css('property');, but this relies on element being on the page. Is there a way of finding out what the property is set to within the CSS rather than the computed style of an element?

Will I have to do something ugly like add a hidden copy of the element to my page so that I can access its style attributes?

Metage answered 25/4, 2010 at 9:47 Comment(0)
M
65

With jQuery:

// Scoping function just to avoid creating a global
(function() {
    var $p = $("<p></p>").hide().appendTo("body");
    console.log($p.css("color"));
    $p.remove();
})();
p {color: blue}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Using the DOM directly:

// Scoping function just to avoid creating a global
(function() {
    var p = document.createElement('p');
    document.body.appendChild(p);
    console.log(getComputedStyle(p).color);
    document.body.removeChild(p);
})();
p {color: blue}

Note: In both cases, if you're loading external style sheets, you'll want to wait for them to load in order to see their effect on the element. Neither jQuery's ready nor the DOM's DOMContentLoaded event does that, you'd have to ensure it by watching for them to load.

Ministration answered 25/4, 2010 at 10:14 Comment(6)
Yes, that's exactly what it is.Ministration
Thought: Make sure it gets nested under the proper element if the style is nested. Ex. CSS: .container .content{} and jQuery: var $p = $("<div class="content"></div>").hide().appendTo("container");Infeudation
Couldn't we get the css property value without even adding the element to the DOM ? Like $('<div class="content" />').css('color') This works for meSouffle
@PierredeLESPINAY: That appear to to work in Firefox, but not in Webkit browsers (tried Chromium and Android 2.x browser).Elsy
Would you be able to do the same with height? cause it seems like it's not really working...Kohn
Thank you for having good jQuery style (var $p in the first example rather than var p). I was completely oblivious to this convention, and seeing your answer made me search around to see why you did it! For anybody reading this comment unfamiliar with the convention, the top two answers to this question explain what is going on very well :)Paderewski
R
19

Normally you should be let the browser apply all the rules and then ask the browser for the results, but for the rare case where you really need to get the value out of the style sheet you can use this: (JSFiddle)

function getStyleSheetPropertyValue(selectorText, propertyName) {
    // search backwards because the last match is more likely the right one
    for (var s= document.styleSheets.length - 1; s >= 0; s--) {
        var cssRules = document.styleSheets[s].cssRules ||
                document.styleSheets[s].rules || []; // IE support
        for (var c=0; c < cssRules.length; c++) {
            if (cssRules[c].selectorText === selectorText) 
                return cssRules[c].style[propertyName];
        }
    }
    return null;
}

alert(getStyleSheetPropertyValue("p", "color"));

Note that this is pretty fragile, as you have to supply the full selector text that matches the rule you are looking up (it is not parsed) and it does not handle duplicate entries or any kind of precedence rules. It's hard for me to think of a case when using this would be a good idea, but here it is just as an example.

Rumal answered 27/5, 2013 at 19:51 Comment(1)
Sadly, css is a horrible language with that 'specificity precedence' principal meaning that this function would only work in about half the cases. Also - selectorText can be different but still point the same elements.Kimberlite
I
7

In response to Karim79, I just thought I'd toss out my function version of that answer. I've had to do it several times so this is what I wrote:

function getClassStyles(parentElem, selector, style){
    elemstr = '<div '+ selector +'></div>';
    var $elem = $(elemstr).hide().appendTo(parentElem);
        val = $elem.css(style);
    $elem.remove();
    return val;
}
val = getClassStyles('.container:first', 'class="title"', 'margin-top');
console.warn(val);

This example assumes you have and element with class="container" and you're looking for the margin-top style of the title class in that element. Of course change up to fit your needs.

In the stylesheet:

 .container .title{ margin-top:num; }

Let me know what you think - Would you modify it, and if so how? Thanks!

Infeudation answered 2/7, 2012 at 1:20 Comment(2)
Great snippet, I adapted it slightly as using a div stopped me from looking up rules constructed like this (table.TreeGrid td.tab) in the style sheet.Tini
I would just suggest to place selector as first attr (and would be fine to parse # and .), "style" attr as second in the function and parentElem as last; than you can make parentElem as not required (and take the global style instead). Next, remember, that parent have posibility to not exists. But really good start point for me, so +1 :-)Volkslied
C
2

I have written a helper function that accepts an object with the css attributes to be retrieved from the given css class and fills in the actual css attribute values. Example is included.

function getStyleSheetValues(colScheme) {
    var tags='';
    var obj= colScheme;
    
    // enumerate css classes from object
    for (var prop in obj) { 
        if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") { 
            tags+= '<span class="'+prop+'"></span>';
        } 
    } 
    
    // generate an object that uses the given classes
    tags= $('<div>'+tags+'</div>').hide().appendTo("body");
    
    // read the class properties from the generated object
    var idx= 0;
    for (var prop in obj) { 
        if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") { 
            var nobj= obj[prop];
            for (var nprop in nobj) { 
                if (nobj.hasOwnProperty(nprop) && typeof(nobj[nprop])=="string") { 
                    nobj[nprop]= tags.find("span:eq("+idx+")").css(nobj[nprop]);
                }
            }
            idx++;
        } 
    } 
    tags.remove();
}

// build an object with css class names where each class name contains one 
// or more properties with an arbitrary name and the css attribute name as its value.
// This value will be replaced by the actual css value for the respective class.
var colorScheme= { chart_wall: {wallColor:'background-color',wallGrid:'color'}, chart_line1: { color:'color'} };

$(document).ready(function() {
    getStyleSheetValues(colorScheme);

    // debug: write the property values to the console;     
    if (window.console) {
        var obj= colorScheme;
        for (var prop in obj) { 
            if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") { 
                var nobj= obj[prop];
                for (var nprop in nobj) { 
                    if (nobj.hasOwnProperty(nprop)) { 
                        console.log(prop+'.'+nprop +':'+ nobj[nprop]);
                    }
                }
            } 
        } 
        // example of how to read an individual css attribute value
        console.log('css value for chart_wall.wallGrid: '+colorScheme.chart_wall.wallGrid);
    }
});
Cypro answered 1/6, 2012 at 21:35 Comment(0)
D
0

I wrote this js function, seems to be working for nested classes as well:

usage:

var style = get_css_property('.container-class .sub-container-class .child-class', 'margin');
console.log('style');


function get_css_property(class_name, property_name){
    class_names = class_name.split(/\s+/);
    var container = false;
    var child_element = false;

    for (var i = class_names.length - 1; i >= 0; i--) {
        if(class_names[i].startsWith('.'))
            class_names[i] = class_names[i].substring(1);
        var new_element = $.parseHTML('<div class="' + class_names[i] + '"></div>');
        if(!child_element)
            child_element = new_element;
        if(container)
            $(new_element).append(container);
        container = new_element;
    }
    $(container).hide().appendTo('body');
    var style = $(child_element).css(property_name);
    $(container).remove();
    return style;
}
Denunciation answered 5/8, 2018 at 20:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.