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

IT技术 javascript css google-chrome
2021-01-27 13:02:08

如何获得元素 CSS 属性(例如宽度/高度),因为它是用 CSS 规则设置的,无论它设置的是什么单位(例如百分比/em/px)?(在 Google Chrome 中,最好是无框架的)。

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

例如:

<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此示例中的所有元素时,我希望能够获得第二个divs 的宽度 as 50%(和第一个 as 100px)。


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

Chrome 元素检查器显示设置时的属性值


不是链接问题的完全重复,因为在那里接受的答案有一个简单的技巧,无论设置什么样的宽度,都会产生一个百分比宽度。至于其余的,您必须知道用于制定活动规则的选择器吗?怎么会知道呢?

5个回答

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

获取匹配样式

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

给出divs的以下宽度

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

(在 jsFiddle )

@ChrisAllinson 遗憾的getMatchedCSSRules()是不再在 Chrome 中工作。Blink 已经放弃了这个,webkit 正在谈论它。在 Chrome 控制台中,您可以看到:'getMatchedCSSRules()' 已弃用。如需更多帮助,请查看code.google.com/p/chromium/issues/detail?id=437569#c2
2021-03-21 13:02:08
它是您编写的一个很棒的函数,但它只返回内联样式规则,而不是 css 中定义的规则。如何得到那些?虽然这是一个非常有用的功能。
2021-04-05 13:02:08
@Pramod,该函数确实返回用 CSS 规则编写的 CSS 值(这就是它的全部内容),如果您仔细查看示例,您就会发现。但它仅适用于支持 的浏览器getMatchedCSSRules(),即 Chrome 和其他基于 WebKit/Blink 的浏览器(如问题中所要求)。太糟糕了,更多的浏览器不支持。尽管 Mozilla 有一个功能请求来实现它:bugzilla.mozilla.org/show_bug.cgi?id=438278
2021-04-08 13:02:08

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

快速阅读本文档,似乎这个可能即将成为规范的目标是简化从 javascript 访问 CSSOM 值的过程。

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

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

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

截至今天,只有 Chrome 实现了它(自 66 起)。

(() => {
  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
  }

*/

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

看起来不错。您的代码示例会为宽度返回什么结果?您能否将其添加到答案中,以便更容易看到它的作用。
2021-03-18 13:02:08
@Qtax 好点,我在代码片段中添加了输出作为注释
2021-04-08 13:02:08

显然没有 DOM API 用于此

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

编辑:oop,刚刚意识到这是为谷歌浏览器标记的

试试 window.getMatchedCSSRules()

有一个较新的重复帖子,这里有一个很好的答案该答案适用于 jQuery,但在纯 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;
}
这不会以与创作的单位相同的单位获得值,但它确实为您提供px,%auto,这对于某些应用程序来说可能已经足够了。所以诀窍是将父级设置为不显示并获取计算样式。有趣的。+1
2021-03-28 13:02:08
这太棒了......我很惊讶它完全有效,但它似乎不适用于视口单位(vh、vw 等)。
2021-04-07 13:02:08

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

这是一个示例的粗略草图,使用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 版本:

注意:上面没有的两件大事是:

  1. 处理从祖先元素继承的样式。如果您只对您知道是继承的单个属性感兴趣,您可以使用上面的,如果它没有设置属性,请为父级重复等。或者可以扩展它以应用基于的继承在属性列表它说,无论他们继承与否和继承规则(小心以允许inheritinitialunset,和revert关键字,以及该all关键字)。

  2. 媒体查询。上面的代码片段只应用所有带有样式的规则。它应该检查CSSMediaRules,查看它们是否与当前媒体匹配(可能使用matchMedia),如果匹配,则进入它们cssRules并应用它们。可能没有那么难。

@TJCrowder 此外,它不适用于媒体查询。
2021-03-18 13:02:08
这仅返回直接应用于元素的样式(在您的情况下为 el),而不是从父元素继承的样式。如果你能展示一个我可以获得所有样式的示例,那就太好了。getComputedStyle()返回一切。
2021-03-22 13:02:08
@AlqamaBinSadiq - 哦,这是个好点子。我在有关它的答案中添加了注释。也许采取以上并运行它,添加继承?如果没有,我可能会为此做一个简单的库,但它必须落后于我列表中的其他几个项目......(不过很有趣。)
2021-03-22 13:02:08
那是我在问题中提到的,请不要将其标记为重复我猜你标记了我的问题并关闭了它。:(
2021-03-30 13:02:08
@AlqamaBinSadiq - 你的问题没有提到继承。事实是,它这个问题的重复,其他人也喜欢它。只是没有很好的答案。:-(
2021-04-07 13:02:08