你能检测到 dom 节点的样式何时设置为“自动”吗?

Posted

技术标签:

【中文标题】你能检测到 dom 节点的样式何时设置为“自动”吗?【英文标题】:Can you detect when a dom node's style is set to 'auto'? 【发布时间】:2011-08-29 15:39:38 【问题描述】:

使用示例 CSS:

.thing  height: auto 

html

<div class="thing">The quick brown fox jumps over a lazy dog.</div>

是否可以检测到.thing的高度设置为'auto'?

以下方法返回值:

jQuery('.thing').height()        // n
jQuery('.thing').css('height')   // 'npx'
getComputedStyle(node).height    // 'npx'

是否有任何方法可以告诉我浏览器正在从“自动”计算这些值?

【问题讨论】:

这本身可能是一个有效的问题,但您是否正在尝试解决更深层次的问题? 是的。动态扩展 CSS3 过渡的行为,以便能够从 height: 20px 过渡到 height: auto ,这是目前没有浏览器可以做到的。 【参考方案1】:

是的,有一种方法,但它不是一个有趣的方法。你要做的是:

    循环遍历所有 styletags 和链接的样式表。

    然后为所有样式标签中的所有cssRules 获取selectorText

    styletag.sheet.cssRules.selectorText
    

    或者对于 IE

    styletag.styleSheet.cssRules.selectorText
    

    获取所有元素的父母idclasstagName,以找出标签获取属性的可能方式。

    在你的元素中找到所有可能的组合 cssRules列表 检查cssRules cssRules.style.width 是否是自动的。

或者做一些相反的方法,找到所有 cssRulesstyle.width == 'auto'; 任何一种方式,如果没有大量代码,这不是一件容易的事

【讨论】:

我担心这可能是答案。 我认为相反的方式可能更理智,因为可以选择我的 div 的可能选择器的数量 - 例如 body > *:first-child - 我不想尝试弄清楚它们都是什么,然后循环查找它们。使用相反的方法,我会: 1. 找到所有宽度 == 'auto' 的 cssRules。 2.用querySelectorAll测试cssRules.selectorText,看看我的div是否被选中。 3. 找出生成的 css 选择器中的哪一个是最重要的。 4. 使用该选择器的宽度属性。不用说,我真的不喜欢那样做 :) 可能有点慢。【参考方案2】:
jQuery('.thing').each(function (i,n)
  console.log( $(n).style.height);// if not then just try to simply find the n.style.height
);

//this is another way // at least in ff it would work :)
window.document.styleSheets[0].cssRules[0].style.height

希望它有所帮助,否则你有很多挖掘工作要做:)

对于第二个选项,您看到[0] 意味着您必须循环,因为可能存在不同的文件名等...

完整示例:

var ss = window.document.styleSheets;
for(i=0;i<ss.length;i++)
    var rules = ss[i].cssRules;
    for(j=0;j<rules.length;j++)//loop style sheets
        var rule = rules[j];
        if(rule.selectorText=='thing')//loop each stylesheet rule
             console.log(rule.style.height);
              // should return height for everytime height is used with every .thing in any of your stylesheets attached :)
        
    

请注意

您必须从跨域中逃脱。例如如果你已经包括 &lt;link ....="...jquery.com.../ui.css" /&gt; 它将不起作用,因为这可能被视为安全风险(跨域)...

【讨论】:

我建议您获取最后一个 rule.style.height,因为那将是最新的 :) 也就是覆盖预览(如果有) 我突然想到可以做这样的事情。 Johan Olsson 的回答更加有力。我需要测试的不仅仅是 selectorText == 'thing'。 body > *:first-child 等选择器可能会影响我的 div。 你可以把所有的东西放在一个函数中,实际上你可以这样搜索它......它可能看起来像 jquery findcss('.thing').height 并且你可以通过使用检查某些事情的函数来扩展它你可以选择模式,这会容易得多:) :)【参考方案3】:

这不是最有效的解决方案,尤其是对于旧 IE 版本,但它应该工作得很好:

    测量元素的高度 向元素添加一些内容,例如&lt;div style="clear: left; height: 30px"&gt;Test&lt;/div&gt; 测试新高度,如果它改变了你的元素有高度自动 删除内容

这是我的实现:

$.fn.hasAutoHeight = function() 
    if (this.length === 0) return;
    var self = this.first();
    var height = self.css("height");
    var position = self.css("position");

    // Check for inline elements
    if (self.css("display") === "inline" && self.css("float") === "none") 
        var position = self.css("position");
        if (position === "static" || position === "relative") return true;  
    

    // Quick check to see if a style height is set
    if ($.style(self[0], "height") !== "") return false;

    // Otherwise use the long route
    var test = $('<div style="clear: both; height: 30px">Test</div>');
    self.append(test);
    var hasAutoHeight = self.css("height") !== height;
    test.css("color", "red").remove();
    return hasAutoHeight;
;

注意事项:

如果 CSS 中有 height: auto !important; 规则,“快速检查”行可能无法正常工作,在这种情况下,您总是需要走很长的路。 这在 DOM 交互方面效率不高,因此您的应用程序希望尽可能缓存此结果。 我不愿意在插件内部缓存结果,因为类/CSS 规则可能会更改并使结果无效。 这不适用于没有正文的元素,例如 &lt;img&gt;&lt;br&gt;

【讨论】:

谢谢!我喜欢这个主意。我将对此进行一些测试。这种东西的圣杯是尽量减少回流的次数,我怀疑这种方法有两三个。我将测试此方法是否会减少我目前正在运行的代码之上的回流总数(假设必须始终测试所有可能的自动值)。尽管问题中的示例是指高度,但我有兴趣检测任何设置为 auto 的属性。此方法可能适用于宽度,但不适用于边距或其他自动属性。 经过一番思考,我不再被这种方法说服了,在 DOM 交互方面仍然有很多,其他解决方案可能同样有效。【参考方案4】:

以下是上述建议的更完整实现:​​

$("*").data("autoHeight", "false");
var stylesheets = window.document.styleSheets;
for (i=0; i < stylesheets.length; i++) 
    var rules = stylesheets[i].cssRules;
    for (j = 0; j < rules.length; j++) 
        var rule = rules[j];
        var style = rule.style.getPropertyValue("height");
        var auto = !style || style.match(/^\s*auto\s*(!important)?$/);
        $(rule.selectorText).each(function() 
            var elem = $(this);
            if (asSpecific(rule.selectorText, $(elem).data("autoHeightSelector"))) 
                $(elem).data("autoHeight", !!auto);
                $(elem).data("autoHeightSelector", rule.selectorText);
            
        );
    

您需要实现 asSpecific(a, b),如果 css 选择器 a 至少与选择器 b 一样具体,则应该可以解决,例如p#foo a#barp.foo 更具体。您还需要考虑!important 标志。

这可能有用:http://www.w3.org/TR/CSS2/cascade.html#specificity

这应该为每个元素添加一个数据属性,指定它是否在 CSS 中具有自动高度样式,但您还需要检查样式属性并考虑默认样式。

【讨论】:

以上是关于你能检测到 dom 节点的样式何时设置为“自动”吗?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法检测 DOM 节点何时要从 DOM 中删除?

检测何时通过 ajax 加载资源

检测何时将 SKNode 添加为子节点

检测用户何时使用 jQuery 滚动到 div 的底部

如何检测何时单击/点击 MapMarker? [复制]

如何让 pcp 自动将节点附加到 postgres pgpool?