获取设置的元素CSS属性(宽度/高度)值(以百分比/ em / px /等为单位)

时间:2012-03-16 01:24:51

标签: javascript css google-chrome

如何使用CSS规则设置元素CSS属性(例如宽度/高度),无论以何种单位设置(例如,百分比/ em / px)? (在谷歌浏览器中,最好是无框架的)。

使用getComputedStyle以像素为单位返回当前值,jQuery中的css()也是如此。

例如:

<div class="b">first</div>
<div id="a" class="a">second</div>

<style>
     div      { width: 100px; }
     x, div#a { width: 50%;   }
     .a       { width: 75%;   }
</style>

在迭代本示例中的所有div元素时,我希望第二个div的宽度为50%(第一个为100px )。


Chrome元素检查器可以显示设置的CSS属性值,因此应该可以在Chrome中显示。

Chrome element inspector showing property value as they were set


链接问题的

不完全重复,因为在接受的答案中有一个简单的hack,无论设置何种宽度,都会产生百分比宽度。其余的你必须知道用于制定活动规则的选择器吗?怎么会知道呢?

5 个答案:

答案 0 :(得分:21)

它不像调用WebKits getMatchedCSSRules()那么简单,它确实按优先级顺序返回匹配的规则(虽然我在文档中没有看到这个顺序),但是顺序没有考虑到属性重要的优先级,不包括元素样式。所以我最终得到了这个功能:

getMatchedStyle

function getMatchedStyle(elem, property){
    // element property has highest priority
    var val = elem.style.getPropertyValue(property);

    // if it's important, we are done
    if(elem.style.getPropertyPriority(property))
        return val;

    // get matched rules
    var rules = getMatchedCSSRules(elem);

    // iterate the rules backwards
    // rules are ordered by priority, highest last
    for(var i = rules.length; i --> 0;){
        var r = rules[i];

        var important = r.style.getPropertyPriority(property);

        // if set, only reset if important
        if(val == null || important){
            val = r.style.getPropertyValue(property);

            // done if important
            if(important)
                break;
        }
    }

    return val;
}

实施例

给出以下代码和样式规则:

<div class="b">div 1</div>
<div id="a" class="a d2">div 2</div>
<div id="b" class="b d3" style="width: 333px;">div 3</div>
<div id="c" class="c d4" style="width: 44em;">div 4</div>

<style>
div      { width: 100px; }
.d3      { width: auto !important; }
div#b    { width: 80%;   }
div#c.c  { width: 444px; }
x, div.a { width: 50%;   }
.a       { width: 75%;   }
</style>

这个JS代码

var d = document.querySelectorAll('div');

for(var i = 0; i < d.length; ++i){
    console.log("div " + (i+1) + ":  " + getMatchedStyle(d[i], 'width'));
}

div s提供以下宽度:

div 1:  100px
div 2:  50%
div 3:  auto
div 4:  44em

At jsFiddle

答案 1 :(得分:5)

显然没有针对此

的DOM API

https://developer.mozilla.org/en/DOM/window.getComputedStyle#Notes

编辑:oops,刚刚意识到这是标记为Google Chrome

尝试window.getMatchedCSSRules()

答案 2 :(得分:3)

有一个较新的重复帖子,答案很清楚here。答案是针对jQuery的,但它很容易实现in pure js

function getDefaultStyle(element, prop) {
    var parent = element.parentNode,
        computedStyle = getComputedStyle(element),
        value;
    parent.style.display = 'none';
    value = computedStyle.getPropertyValue(prop);
    parent.style.removeProperty('display');
    return value;
}

答案 3 :(得分:3)

大家好消息!在w3c草案中似乎有CSS Typed OM

快速阅读本文档,似乎这个可能是规范的目标是简化javascript对CSSOM值的访问。

这对我们来说真正重要的部分是我们将有一个CSSUnitValue API,它能够将CSS值解析为表单的对象

{
  value: 100,
  unit: "percent", // | "px" | "em" ...
  type: "percent"  // | "length"
}

并在Element接口中添加computedStyleMap()方法,我们将从中获取实际应用于元素的值。

截至今天,only Chrome implements it(自66年起)。

&#13;
&#13;
(() => {
  if (!Element.prototype.computedStyleMap) {
    console.error("Your browser doesn't support CSS Typed OM");
    return;
  }
  document.querySelectorAll('.test')
    .forEach((elem) => {
      let styleMap = elem.computedStyleMap();
      const unitvalue = styleMap.get('width');
      console.log(elem, {
        type: unitvalue.type(),
        unit: unitvalue.unit,
        value: unitvalue.value
      });
    });

/* outputs

  <div class="b test">first</div> {
    "type": {
      "length": 1
    },
    "unit": "px",
    "value": 100
  }
  
  <div id="a" class="a test">second</div> {
    "type": {
      "percent": 1
    },
    "unit": "percent",
    "value": 50
  }

*/

})();
&#13;
div.test {  width: 100px; }
x,div#a {  width: 50%; }
.a {  width: 75%; }
&#13;
<div class="b test">first</div>
<div id="a" class="a test">second</div>
&#13;
&#13;
&#13;

答案 4 :(得分:2)

我很惊讶没有看到这个答案,因此:您可以自己浏览样式表并获取有关与元素匹配的规则的信息。

这是一个示例的粗略草图,使用specificity库来计算选择器特异性。 getComputedStyle会告诉您这些尺寸(以像素为单位),而不是原始单位。

function applyStyles(target, style, specificity, appliedSpecs) {
    // Loop through its styles
    for (let [key, value] of Object.entries(style)) {
        // Skip the numerically-indexed ones giving us property names
        if (/^\d+$/.test(key)) {
            continue;
        }
        if (value !== "") {
            // Non-blank style. If it has !important, add to specificity.
            let thisSpec = specificity;
            if (style.getPropertyPriority(key) === "important") {
                // Important rule, so bump the first value (which will currently be 0
                // for a stylesheet style and 1 for an inline style
                thisSpec = [specificity[0] + 1, ...specificity.slice(1)];
            }
            // Non-blank style, do we have a style already and if so, with
            // what specificity?
            const currentSpec = appliedSpecs[key];
            if (!currentSpec || SPECIFICITY.compare(thisSpec, currentSpec) >= 0) {
                // Either we didn't already have this style or this new one
                // has the same or higher specificity and overrides it.
                target[key] = value;
                appliedSpecs[key] = thisSpec;
            }
        }
    }
}

function getDeclaredStyle(el) {
    // An object to fill in with styles
    const style = {};
    // An object to remember the specificity of the selector that set a style
    const appliedSpecs = {};
    // Loop through the sheets in order
    for (const sheet of Array.from(el.ownerDocument.styleSheets)) {
        // Loop through the rules
        const rules = sheet.cssRules || sheet.rules;
        if (rules) {
            for (const rule of Array.from(rules)) {
                const {selectorText} = rule;
                if (selectorText && el.matches(selectorText)) {
                    // This rule matches our element
                    if (rule.style) {
                        // Get the specificity of this rule
                        const specificity = SPECIFICITY.calculate(selectorText)[0].specificityArray;
                        // Apply these styles
                        applyStyles(style, rule.style, specificity, appliedSpecs);
                    }
                }
            }
        }
    }
    // Apply inline styles
    applyStyles(style, el.style, [0, 255, 255, 255], appliedSpecs);
    return style;
}

// Get the element
const el = document.querySelector("div.a.b");

// Get its declared style
const style = getDeclaredStyle(el);

// Height is 3em because .a.b is more specific than .a
console.log("height:      " + style.height);      // "3em"
// Width is 5em because of the !important flag; it overrides the inline style rule
console.log("width:       " + style.width);       // "5em"
// Border width is 1em because the rule is later than the other rules
console.log("line-height: " + style.lineHeight);  // "1.2"
// Color is blue because the inline style rule is !important
console.log("color:       " + style.color);       // "blue"

// Compare with results of `getComputedStyle`:
const computed = getComputedStyle(el);
console.log("computed height:      " + computed.height);
console.log("computed width:       " + computed.width);
console.log("computed line-height: " + computed.lineHeight);
console.log("completed color:      " + computed.color);
.a {
    width: 1em;
    height: 1em;
    width: 5em !important;
    color: red !important;
    line-height: 1.0;
    color: yellow !important;
}
.a.b {
    height: 3em;
}
.a {
    height: 2em;
    width: 4em;
    line-height: 1.2;
}
.as-console-wrapper {
    max-height: 100% !important;
}
<script src="//unpkg.com/specificity@0.4.1/dist/specificity.js"></script>
<div class="a b" style="width: 4em; color: blue !important">x</div>

再次,这只是一个草图,但它应该以正确的方式引导您...

这是ES5版本:

// Get the element
var el = document.querySelector("div.a.b");
// An object to fill in with styles
var style = {};
// An object to remember the specificity of the selector that set a style
var specificity = {};
// Loop through the sheets in order
for (var sheetIndex = 0; sheetIndex < document.styleSheets.length; ++sheetIndex) {
    var sheet = document.styleSheets[sheetIndex];
    // Loop through the rules
    var rules = sheet.cssRules || sheet.rules;
    if (rules) {
        for (var ruleIndex = 0; ruleIndex < rules.length; ++ruleIndex) {
            var rule = rules[ruleIndex];
            var selectorText = rule.selectorText;
            if (selectorText && el.matches(selectorText)) {
                // This rule matches our element
                if (rule.style) {
                    // Get the specificity of this rule
                    var spec = SPECIFICITY.calculate(selectorText)[0].specificityArray;
                    // Loop through its styles
                    for (var key in rule.style) {
                        // Skip inherited ones and the numerically-indexed ones giving us property names
                        if (/^\d+$/.test(key) || !rule.style.hasOwnProperty(key)) {
                            continue;
                        }
                        var value = rule.style[key];
                        if (value !== "") {
                            // Non-blank style. If it has !important, add to specificity
                            var thisSpec = spec;
                            if (rule.style.getPropertyPriority(key) === "important") {
                                thisSpec = spec.slice();
                                thisSpec[0] = 1;
                            }
                            // Non-blank style, do we have a style already and if so, with
                            // what specificity?
                            var currentSpec = specificity[key];
                            if (!currentSpec || SPECIFICITY.compare(thisSpec, currentSpec) >= 0) {
                                // Either we didn't already have this style or this new one
                                // has the same or higher specificity and overrides it
                                style[key] = value;
                                specificity[key] = thisSpec;
                            }
                        }
                    }
                }
            }
        }
    }
}

// Height is 3em because .a.b is more specific than .a
console.log("height:      " + style.height);       // "3em"
// Width is 5em because of the !important flag
console.log("width:       " + style.width);       // "5em"
// Border width is 1em because the rule is later than the other rules
console.log("line-height: " + style.lineHeight); // "1.2"

// Compare with results of `getComputedStyle`:
var computed = getComputedStyle(el);
console.log("computed height:      " + computed.height);
console.log("computed width:       " + computed.width);
console.log("computed line-height: " + computed.lineHeight);
.a {
    height: 1em;
    width: 5em !important;
    line-height: 1.0;
}
.a.b {
    height: 3em;
}
.a {
    height: 2em;
    width: 4em;
    line-height: 1.2;
}
<script src="//unpkg.com/specificity@0.4.1/dist/specificity.js"></script>
<div class="a b"></div>

注意:上述做的两件事是:

  1. 从祖先元素继承的句柄样式。如果您只对知道继承的单个属性感兴趣,则可以使用上面的属性,如果没有设置该属性,请对父属性重复,等等。或者可以扩展该属性以基于list of properties(说明它们是否被继承)和rules of inheritance(小心允许inheritinitialunset和{{ 1}}关键字以及revert关键字)。

  2. 媒体查询。上面的代码段仅适用于所有带有样式的规则。它应该检查CSSMediaRules,查看它们是否与当前媒体匹配(可能使用matchMedia),如果匹配,请进入其all并应用它们。也许不是那么难。