简体   繁体   中英

JavaScript get list of styles currently applied to an element

List only rendered styles, not arbitrary ones that aren't applied

I've tried many things to get the styles applied to an element but have come up blank.

Please do not cite getComputedStyle as being a solution unless you can solve the junk returns issue.

The primary problem is that window.getComputedStyle(document.querySelector('ANY ELEMENT')).fill will return "rgb(0, 0, 0)" , which is not the correct style in almost any instances, and has no apparent way to destinguish if its actually being applied or not.

The above example is not the only problem case; there are tons of rules returned by getComputedStyle which are wrong and will drastically change the look of the page if they are applied.

Static parsing is not an option as there are cases where the .css files are on another server with no cross-origin headers; which also hides styles usually found in document.styleSheets .

Is there any way to get a list of the applied styles and nothing else?

As requested this code will demonstrate the problem (on Chrome):

var all = document.getElementsByTagName('*');
for(var i in all)
    if (all[i].style) all[i].style.cssText = window.getComputedStyle(all[i]).cssText;

EDIT: My answer has code which works on all browsers. I keep above to preserve comment thread.

Here are the version that don't need to check depth. The problem in your code is the assign of inline style in the previous element will affect the getComputedStyle result of the next result. It mean the value of getComputedStyle is always changing in the loop. You can first store it in an array like this.

var all = document.getElementsByTagName('*');
tmpArr = []
for(var i in all) {
    if (all[i].style) {
        tmpArr[i] = window.getComputedStyle(all[i]).cssText;
    }
}
for(var i in all) {
    if (all[i].style) {
        all[i].style.cssText = tmpArr[i]; ;
    }
}
console.log("finish");

You can change tmpArr[i] = window.getComputedStyle(all[i]).cssText; to tmpArr[i] = window.getComputedStyle(all[i]).cssText + "-webkit-text-fill-color:#691099!important"; to test whether it work

It will be slow if you open the inspector since there are too much inline style, but it will solve the problem if all you need is just put the style to be inline style.

Partial Answer (Updated):

It is possible to get only the active styles by calling my function getRenderedStyles :

getRenderedStyles now bypasses active stylesheets for more accurate output.

function getRenderedStyles(element) {
    var tmpele, tmpstyle, elestyle, varstyle, elecolor, eletag;
    var styles   = {};
    var defstyle = {};
    elestyle   = window.getComputedStyle(element);
    elecolor   = elestyle.color; 
    eletag     = element.tagName;
    var frag = document.createDocumentFragment();
    frag.appendChild(document.documentElement);
    tmpele   = document.appendChild(document.createElement(eletag));
    tmpstyle = window.getComputedStyle(tmpele);
    styles['color']     = elecolor===tmpstyle.color?undefined:elecolor;
    tmpele.style.color  = elecolor; // workaround for color propagation on other styles 
    for (var i in tmpstyle)
        defstyle[i] = tmpstyle[i];
    tmpele.remove();
    document.appendChild(frag);
    varstyle = element.style;
    for (var i in varstyle) {
        if ((((typeof varstyle[i])==="string"))&&(i!=="cssText")) {
            if ((defstyle[i]!==elestyle[i]))
                styles[i] = elestyle[i];
        }
    }
    return styles;
}

Sadly there's a caviat as the browser still seemingly returns invalid styles in some cases. Often shifting the locations of elements.

To verify this you may run the following code, which takes into account parent/child inheritance , in an attempt to properly apply the current styles to the page:

function DOMDepth(element) {
    var cur  = element;
    var deep = 0;
    while(cur.parentNode)
        deep++, cur = cur.parentNode;
    return deep;
}

function getElementsByDepth() {
    var all = document.getElementsByTagName('*');
    var depth_map = {};
    var deepest   = 0;
    for(var i in all) {
        var depth = DOMDepth(all[i]);
        deepest   = depth>deepest?depth:deepest;
        depth_map[depth] = depth_map[depth] || [];
        depth_map[depth].push(all[i]);
    }
    depth_map['deepest'] = deepest;
    return depth_map;
}

function inlineComputedStyles() {
    var depth_map = getElementsByDepth();
    for (var i = depth_map.deepest; i>0; i--) {
        var elements = depth_map[i];
        for (var j in elements) {
            var styles = getRenderedStyles(elements[j]);
            for (var k in styles) {
                elements[j].style[k] = styles[k];
            }
        }
    }
}

I have tested the preceeding and can confirm it does not suffer the color problems of the snippet in the question. Sadly I am uncertain as to why some elements still shift or if there's a way to fix it.

Special thanks to Kit Fung for pointing out the inheritance problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM