admin管理员组

文章数量:1291913

I can get all css properties for an element with document.stylesheets but some of those are not active because those properties are overwritten. In firebug (chrome developer tools also has this feature), if there's an overwritten css property, you will see something like that:

The only way I can think of is paring active css property for the element (in jQuery $(element).css(property)) and defined css property in document.stylesheets but it's not a reliable way to do it. Any suggestion?

I can get all css properties for an element with document.stylesheets but some of those are not active because those properties are overwritten. In firebug (chrome developer tools also has this feature), if there's an overwritten css property, you will see something like that:

The only way I can think of is paring active css property for the element (in jQuery $(element).css(property)) and defined css property in document.stylesheets but it's not a reliable way to do it. Any suggestion?

Share Improve this question edited Jun 30, 2013 at 15:16 Yotam Omer 15.4k11 gold badges64 silver badges65 bronze badges asked Jun 6, 2012 at 15:21 burak emreburak emre 1,6014 gold badges27 silver badges48 bronze badges 5
  • The browser has to know, because it calculates the specificity of the selectors to determine the final oute. All the Dev Tools are doing is keeping track of those calculations and showing you them. To do the same in JS, you'd have to construct an entire CSS parser... – Niet the Dark Absol Commented Jun 6, 2012 at 15:27
  • @Kolink, thanks. it seems there's no way to track browser's calculations without any extension, right? – burak emre Commented Jun 6, 2012 at 15:45
  • I may be missing something but I can see in DevTools that overwritten properties are crossed over in the same way as they are in firebug (imgur./W9liZs8). So, what's the issue here? – Konrad Dzwinel Commented Aug 12, 2013 at 8:55
  • 1 Why are you trying to do this? Is there an underlying problem that this may solve? (if so, maybe we can help with other solutions to THAT problem.) – andi Commented Aug 14, 2013 at 15:32
  • @andi this can be useful for website builders, and apps like that. – iConnor Commented Aug 16, 2013 at 11:42
Add a ment  | 

3 Answers 3

Reset to default 8 +100

In webkit, you can use getMatchedCSSRules to achieve what you want. It returns a CSS Rule set in order of inheritance applied by the browser and it is what the webkit inspector used some time ago. For Gecko based browsers like Firefox there seems to be a polyfill available here although I've not tested it.

A basic, working solution

The following code is also available as a fiddle

Because getMatchedCSSRules only works with inline stylesheets, you will first have to inline your linked stylesheets:

function inlineStyles() {
    var stylesheets = document.getElementsByTagName('link'),
        head = document.getElementsByTagName('head')[0];

    for (var i = 0; i < stylesheets.length; i++) {
        if (stylesheets[i].getAttribute('rel') == 'stylesheet') {
            (function (stylesheet) {
                var xmlhttp = new XMLHttpRequest();
                xmlhttp.open("GET", stylesheet.getAttribute('href'), true);
                xmlhttp.onreadystatechange = function () {
                    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                        var inlineStyle = document.createElement('style');
                        inlineStyle.setAttribute('type', 'text/css');
                        inlineStyle.innerText = xmlhttp.responseText;
                        head.replaceChild(inlineStyle, stylesheet);
                    }
                };
                xmlhttp.send();
            })(stylesheets[i]);
        } else {
            continue;
        }
    };
}

Then, the big chunk: This is a first shot, improve at will. It can handle inherit rules and up to one !important definition, but that's it. For really plicated setups, this will have to be improved:

function getStyle(s, id) {
    var element = typeof id === 'string' ? document.getElementById(id) : id,
        css = window.getMatchedCSSRules(element),
        style = window.getComputedStyle(element),
        value = style[s],
        styles = [],
        rules = [],
        inherited, currentRule;

    // if there's a puted style, start calculation
    if (value) {

        // add matched rules if there are any
        if (css) {
            for (var i = 0; i < css.length; i++) {
                styles.push(css[i]);
            }
        }

        // add the element style attribute as a matched rule
        styles.push({
            style: element.style,
            cssText: 'element.style {' + element.getAttribute('style') + ' }'
        });

        for (var i = styles.length - 1; i >= 0; i--) {
            var def = styles[i],
                rule = {
                    index: rules.length,
                    style: s,
                    value: styles[i].style[s],
                    cssText: def.cssText
                };

            if (rule.value == 'inherit' && !currentRule) {
                if (inherited = getInherited(element, s, value)) {
                    rule.inheritedFrom = inherited;
                    currentRule = rule;
                    inherited = undefined;
                } else {
                    rules.push(rule);
                }
            } else if (rule.value == 'inherit' && currentRule && isImportant(s, value, def.cssText)) {
                if (inherited = getInherited(element, s, def)) {
                    rule.inheritedFrom = inherited;
                    rules.splice(currentRule.index, 0, currentRule);
                    currentRule = rule;
                    inherited = undefined;
                } else {
                    rules.push(rule);
                }
            } else if (rule.value == value && !currentRule) {
                currentRule = rule;
            } else if (rule.value == value && currentRule && isImportant(s, value, def.cssText)) {
                rules.splice(currentRule.index, 0, currentRule);
                currentRule = rule;
            } else if (rule.value.length) {
                rules.push(rule)
            }
        }

        return {
            current: currentRule,
            overwritten: rules
        };

    } else {
        return false;
    }
}

If Inheritance is taking place, we walk up the DOM Nodes to find the element that defines the CSS Rule with this helper function and get its style:

function getInherited(element, s, value) {
    while (element.parentNode && window.getComputedStyle(element.parentNode)[s] == value) {
        element = element.parentNode;
    }

    if (element) {
        return getStyle(s, element).current;
    } else {
        return null;
    }
}

We determine if a CSS Rule is marked as important with this helper function:

function isImportant(s, style, text) {
    return new RegExp(s.replace(/([A-Z])/g, '-$1').toLowerCase() + ':\\s+' + style + '\\s+!important').test(text)
}

Have a look at the fiddle to see it working

This snippet may be useful to you, its helped me in the past, apply it in one of your CSS files, and you will be able to see what objects are being overridden by other class / id rules by finding the specific places where elements CSS declarations are, and by tracking their parents. My guess is you're having issues with inheritance.

* { outline: 2px dotted red }
* * { outline: 2px dotted green }
* * * { outline: 2px dotted orange }
* * * * { outline: 2px dotted blue }
* * * * * { outline: 1px solid red }
* * * * * * { outline: 1px solid green }
* * * * * * * { outline: 1px solid orange }
* * * * * * * * { outline: 1px solid blue }

Alternatively you could add a :hover attribute to those, and it would make it a bit easier to navigate, but the basic principal of the snippet is to show you the nesting of elements, and may help you to determine where the issues in your CSS are

You would have to parse the CSS files that are linked to the page to be able to determine the styles that are being used. You would also have to determine what properties can be used to target elements in CSS. Here is the flow you would have to follow:

Elements can be targets by: tags, IDs, classes, pseudo classes and inheritance

You would then have a given element, for instance:

<a href="#" id="link" class="button">Woop</a>

That element has several selectors associated to it by default. All elements can inherit parent CSS, so you would have to create a hierarchy of parent elements. Later styles will take precedence. You then have to take into account the tag a and any parent that also shares this selector such as body a. Likewise, you would have to create a hierarchy of inherited attributes. You would repeat this process for classes, attributes, and pseudo-classes. Once you have piled your list of trees for the element, you can then parse the CSS documents for the appropriate styles.

This is definitely a huge undertaking and there is no sense in reinventing the wheel. What I would suggest is looking at open source projects that have already done this. WebKit is an open-source project that has already built this system. Consider using their implementation as a starting point and make your changes from there.

本文标签: javascriptHow can I detect overwritten css propertiesStack Overflow