【问题标题】:How can I tell if a particular CSS property is inherited with jQuery?如何判断一个特定的 CSS 属性是否被 jQuery 继承?
【发布时间】:2011-02-15 05:13:20
【问题描述】:

这是一个非常简单的问题,所以我会保持简短:

如何判断特定 DOM 元素的 CSS 属性是否被继承?

我问的原因是因为jQuerycss 方法将返回计算的样式,该样式继承父对象的CSS 属性。有没有办法检索对象本身设置的属性?

一个例子可能会更好地解释我的理解:

CSS:

div#container {
  color:#fff;
}

HTML:

<div id="container">
  Something that should be interesting
  <div class="black">
    Some other thing that should be interesting
  </div>
</div>

那么,在继承colordiv.black 的实例中,我如何判断它是否被继承?

$('div.black:eq(0)').css('color') 显然会给我#fff,但我想检索元素本身的样式,而不是它的父元素。

【问题讨论】:

    标签: jquery css


    【解决方案1】:

    要真正确定 CSS 样式是继承还是设置在元素本身上,您必须实施浏览器应用的确切规则,以确定元素上特定样式的使用值。

    您必须实现这个spec,它指定计算值和使用值的计算方式。

    CSS 选择器可能并不总是遵循可以简化问题的父子关系。考虑一下这个 CSS。

    body {
        color: red;
    }
    
    div + div {
        color: red;
    }
    

    以及以下 HTML:

    <body>
        <div>first</div>
        <div>second</div>
    </body>
    

    firstsecond 都将显示为红色,但是,第一个 div 是红色的,因为它从父级继承。第二个 div 是红色的,因为 div + div CSS 规则适用于它,这更具体。查看父级,我们会看到它具有相同的颜色,但这不是第二个 div 的来源。

    浏览器不公开任何内部计算,getComputedStyle 接口除外。

    一个简单但有缺陷的解决方案是遍历样式表中的每个选择器,并检查给定元素是否满足选择器。如果是,则假定该样式直接应用于元素。假设您想浏览第一个样式表中的每种样式,

    var myElement = $('..');
    var rules = document.styleSheets[0].cssRules;
    for(var i = 0; i < rules.length; i++) {
        if (myElement.is(rules[i].selectorText)) {
            console.log('style was directly applied to the element');
        }
    }
    

    【讨论】:

    • 感谢您的回答。那么什么是好的解决方案呢?
    • @Jacob - 一个好的健壮解决方案必须实现链接的 w3 spec,并跟踪样式继承。 Josh 的回答适用于 css 选择器遵循父子关系的情况(参见div + div 的反例)。如果该选择器没有被更具体的选择器覆盖,例如 #someId 击败 div,则在我的示例中循环遍历 CSS 选择器。
    • 特异性和继承是两个不同的问题——div + div 规则的存在就是使第二个 div 变红的原因;它比body 更具体这一事实完全无关紧要,因为一个适用于 div 而另一个适用于页面正文。
    • @BoltClock - body 选择器存在这一事实很重要,因为如果div + div 选择器不存在,那么由于继承,div 的颜色仍将是红色。在没有这个特定选择器的情况下,继承获胜。当特定的选择器存在时,它胜过继承。
    • 是的,但这与选择器的特异性没有任何关系。
    【解决方案2】:

    我认为您无法判断给定样式是否被继承,我认为您能做的最好的事情是将给定的 CSS 属性设置为“继承”,捕获其计算值,并将其与原始值进行比较。如果它们不同,则样式肯定是继承的。

    var el = $('div.black:eq(0)');
    var prop = el.css("color");
    el.css("color", "inherit");
    var prop2 = el.css("color");
    el.css("color", prop);
    if(prop != prop2)
      alert("Color is not inherited.");
    

    Demo on jsFiddle

    重点是:如果你在CSS中或者通过内联样式将div.black设置为#fff,这个方法会认为是继承的。在我看来,这并不理想,但它可能适合您的需求。恐怕一个完美的解决方案需要遍历整个样式表。

    【讨论】:

      【解决方案3】:

      http://jsfiddle.net/k7Dw6/

      var $black = $('div.black:eq(0)');
      alert($('<div>').attr('class', $black.attr('class')).css('line-height') === $black.css('line-height'));
      

      您可以创建一个具有相同类(我猜是 ID)的新元素并检查 CSS 属性是否相同。

      【讨论】:

      • 新元素需要作为兄弟元素插入到 DOM 中才能继承相同的样式...
      • @Josh:什么!??这正是想要的。创建一个新元素的全部意义在于它不会继承任何东西,因此我们可以比较这些值是来自继承还是来自类。
      • @Mark - 你不应该依赖 OP 给出的例子来解决一般问题。选择器可以得到极大的complex - 它们可以组合。只有当它出现在某个文档结构中时,样式也可以来自一个类。如果 CSS 选择器是 - div &gt; div.black 怎么办?然后,您必须创建两个 div,将一个嵌套在另一个内部,并将 "black" 类分配给内部 div 以获得 line-height 样式,然后进行任何比较。
      • @Anurag:这也没有意义,我的解决方案通用的。 $black 只是他要检查的元素的名称,line-height 是他要检查的属性——很容易替换。谁在乎 CSS 选择器是什么?我不在乎 如何 值被继承,只是它确实如此。如果……好吧。没关系,我明白你现在在说什么了。我想这取决于你如何定义“继承”然后......呃。在父母身上设置一个值与在孩子身上设置它通常一样好......但我称之为继承,但如果你想在邻居上设置它......
      • @Mark - 我提供选择器链接的原因是为了展示它们的复杂性以及它们并不总是遵循父子关系的事实。一般来说,可以有属性选择器 -div[data-type="person"] &gt; span.name、结构选择器 -div:nth-child(odd),或者根据用户交互改变状态的选择器 -div:hover。这只是一小部分示例,用于说明为什么简单的父子假设可能不适用于所有情况。虽然其中一些选择器可能不常见,但它们的存在使问题变得更加复杂。
      【解决方案4】:

      我知道这是一个老问题,但是我想我会分享我对 Josh 的回答所做的事情,即:修改它以删除 css(如果它是继承的),并将其变成一个 jQuery 插件。请随意将其击落,但到目前为止它对我有用:-)

      $.fn.isInheritedStyle = function(style) {
          var current = this.css(style);
          this.css(style, 'inherit');
          var inherited = this.css(style);
          if (current == inherited)
              this.css(style, '');
          else
              this.css(style, current);
          return (current == inherited);
      }
      

      【讨论】:

        【解决方案5】:

        JS(不是 jQuery)element.style 属性返回一个 CSSStyleDeclaration 对象,因此:

        {parentRule: null, 
        length: 0, 
        cssText: "", 
        alignContent: "", 
        alignItems: ""…
        

        如果您感兴趣的样式有一个值,那么它在元素级别被声明(或由 JS 应用),否则被继承。
        信息来自https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style

        我在 HTML5 Dnd 中苦苦挣扎,在元素级别 (li) 添加 display:list-item 并破坏了另一个隐藏/显示过滤器功能;我能够以这种方式修复它。
        我的具体代码是:

        // browser bug? it adds display:list-item to the moved elements, this
        // loops clear the explicit element-level "display" style
        var cols = $('#columnNames li');
        for( var icol = 0; icol < cols.length; icol++) {
            var d = cols[icol].style; // the CSSStyleDeclaration 
            d.display = ""; // clear the element-level style
        }
        

        【讨论】:

        • 否则它是从 CSS 样式或样式表派生的。
        【解决方案6】:

        如果您对样式与父元素的不同之处感兴趣,您可以通过 $('div.black:eq(0)').parent( ).css('行高')。通过这种方式,您可以判断孩子和父母是否具有相同的价值。但是,您可以从中收集到的信息是有限的。有可能孩子和父母都被明确分配了相同的东西!

        如果您对级联的更复杂的结构感兴趣(例如,就像您在 firebug 中看到的那样),那么我没有一个只使用 jQuery 的好答案。根据您想要的特定信息,您可以执行一些低效的 hack(例如按照其他人的建议克隆对象,或切换类并检查切换的效果),但想想就让我心烦意乱!

        正如我认为有人指出的那样,vanilla JS 确实允许您检查特定样式项目的属性;所以也许 jQuery 和 vanilla JS 的混合体可以满足您的需求?

        查看http://developer.apple.com/internet/webcontent/styles.html 以查看可让您访问样式表信息的 javascript。 AFAIK 这不会是 jQuery 的“开箱即用”类型的东西(可能完全是错误的)。也就是说,如果您愿意遍历样式表信息,这应该是可能的。

        编辑:根据原始问题的示例代码删除了一些内容

        【讨论】:

        • 好吧,我很在乎。重点是检查样式是否级联。
        • 也许您可以就您的具体用例向我们提供一些见解?请注意,在您的示例中,5em 不是继承的,而是实际上分配给内部 div,因为该样式适用于所有 div 元素。即使内部 div 根本没有被包裹,它也会是 5 em。这里真正的问题是样式可以通过多种方式级联。
        • 没问题 - 很抱歉听起来很困惑!我已经更新了我的答案,虽然我没有使用 jQuery 的答案;我只知道 JS 可以通过一些技巧让您提取工作表本身内部定义的样式信息。
        【解决方案7】:

        我认为,这是 jquery 的好行为。当$('div.black:eq(0)').css('line-height')、false 或 undefined 时,你想得到什么?这太令人困惑了,因为line-height(继承,是的)的实际值是 1 em。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-09
          • 1970-01-01
          相关资源
          最近更新 更多