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

Posted

技术标签:

【中文标题】获取设置的元素 CSS 属性(宽度/高度)值(以百分比/em/px/等为单位)【英文标题】:Get element CSS property (width/height) value as it was set (in percent/em/px/etc) 【发布时间】:2012-04-01 14:28:49 【问题描述】:

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

使用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 元素时,我希望能够将第二个divs 宽度设为50%(第一个为100px)。


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


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

【问题讨论】:

这个答案可能就是你想要的:***.com/a/744450/684934 这些答案根本不合适,因为我需要通过元素以某种方式获取值,而不是在某些特定的选择器上。 不完全重复! % 仅与其父元素的上下文相关,因此您需要根据当前和父元素的比较宽度来计算它 $(element).style.width 对我有用..? @Dan,没有。 element.style.width 仅在元素具有 style 属性并设置了 width 时才返回值。 【参考方案1】:

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

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

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

    从祖先元素继承的句柄样式。如果您只对您知道是继承的单个属性感兴趣,您可以使用上面的方法,如果它没有设置属性,请重复父级等。或者可以扩展它以应用继承基于list of properties 表示它们是否被继承,rules of inheritance(注意允许 inheritinitialunsetrevert 关键字,以及 all关键字)。

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

【讨论】:

这仅返回直接应用于元素的样式(在您的情况下为 el),而不是从父级继承的样式。如果您能展示一个我可以获得所有样式的示例,那就太好了。 getComputedStyle() 返回所有内容。 @AlqamaBinSadiq - 哦,这是一个好点。我已经在关于它的答案中添加了注释。也许采取上述并运行它,添加继承?如果没有,我可能会为此做一个简单的库,但它必须落后于我名单上的其他几个项目......(虽然很有趣。) 那是我在问题中提到的请不要将其标记为重复我猜您标记了我的问题并关闭了它。 :( @AlqamaBinSadiq - 你的问题没有提到继承。事实是,它这个问题和其他类似问题的重复。只是没有一个好的答案。 :-( @T.J.Crowder 此外,它不适用于媒体查询。【参考方案2】:

大家好消息! 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 岁起)。

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

【讨论】:

看起来不错。您的代码示例将为宽度返回什么结果?您能否将其添加到答案中,以便更容易看到它的作用。 @Qtax 好点,我在代码的 sn-p 中添加了输出作为注释【参考方案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;

【讨论】:

这不会获得与所创作单位相同的值,但它确实为您提供px%auto,这对于某些应用程序可能已经足够了。所以诀窍是将父级设置为不显示并获取计算样式。有趣的。 +1 这太棒了......我很惊讶它完全可以工作,但它似乎不适用于视口单位(vh、vw 等)。【参考方案4】:

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

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 = getMatchedCs-s-rules(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

(At jsFiddle)

【讨论】:

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

显然没有用于此的 DOM API

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

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

试试 window.getMatchedCs-s-rules()

【讨论】:

以上是关于获取设置的元素 CSS 属性(宽度/高度)值(以百分比/em/px/等为单位)的主要内容,如果未能解决你的问题,请参考以下文章

CSS3圆角属性详解

css实现宽度与高度成比例

js里关于各种尺寸的获取

将元素高度/宽度设置为百分比和像素值的组合[重复]

background设置不平铺后图片消失

在CSS中如何让父元素的宽度等于其子元素的宽度之和?