后代组合器CSS定义的顺序

时间:2019-02-07 03:22:50

标签: html css html5

对于那里的HTML忍者来说,这肯定是一个非常简单的问题,但是我觉得这里缺少明显的东西。这是一个片段:

#red span {
  color: red;
}

#green span {
  color: green;
}
<div id="red">
  <p><span>red</span></p>
  <div id="green">
    <p><span>green</span></p>
  </div>
</div>

如果交换样式表顺序,所有文本将变为红色:

#green span {
  color: green;
}

#red span {
  color: red;
}
<div id="red">
  <p><span>red</span></p>
  <div id="green">
    <p><span>green</span></p>
  </div>
</div>

尽管<div id="green">是DOM树中<span>green</span>的内部父级比<div id="red">多得多,但还是会发生这种情况。我想它的优先级并不简单,因为它的CSS现在按样式表的顺序首先出现。因此,样式表的顺序在这里很重要。

这是预期的行为吗?该实现/浏览器是否特定?有一些官方规范对此进行详细说明吗?

最后,在不依赖样式表的顺序或添加新的类名,id等的情况下,我是否可以使用任何CSS选择器语法使它像第一个代码片段中那样工作?

3 个答案:

答案 0 :(得分:1)

您可以使用>选择器使其仅适用于具有您提供的ID的div中的特定范围,而不适用于div中的所有范围

#green > span {
  color: green;
}

 span {
  color: red;
}
<div id="red">
  <p><span>red</span></p>
  <div id="green">
    <span>green</span>
  </div>
</div>

答案 1 :(得分:1)

是的,您得到的结果是绝对预期的-好吧,也许不是 expected ,但它们是正确的。这是official specs。这里是tweet poll of mine,详细说明了完全相同的问题。 (剧透:大多数选民都错了。)请阅读答复,以进行更深入的讨论。

当前,没有任何CSS技术考虑“最亲近的”范围。这是很多程序员普遍的误解。 (CSS不是一种编程语言。)一个典型的程序员会想到:“选择器#red span意味着我看到#red的任何地方,在里面寻找span,然后应用样式。由于#green span#red内部 ,因此绿色将应用在红色之后。”这完全是不正确的。

CSS 实际上应用样式的方式是,它查看每个元素,然后从上到下遍历样式表,确定其是否匹配,然后随即应用/覆盖样式。这只是层叠的一个方面,其中的其他方面(such as inheritance and specificity)。由于在您的第二个示例中,#red span在CSS源代码中排在最后,因此无论#green span在“ span”内位于“ {close}多近”,它都将被应用,覆盖#red。 DOM。

要解决您的特定问题,最简单的方法是使用直接子选择器,例如#red > p > span#green > p > span。但您可能会怀疑,如果您更改HTML,则必须更新这些选择器。 CSS和HTML的耦合很麻烦,尤其是随着项目的发展。

最佳策略不依赖DOM来设置元素样式。将span移到#red外面会怎样?您想要它保持其风格吗?对于可维护且可伸缩的CSS,您应该仅使用类(而不是ID),并将该类应用于要设置样式的实际元素,而不取决于DOM结构或父子关系。这样,当HTML结构发生变化时,您无需调整CSS即可匹配。

示例:

.red {
  color: red;
}
.green {
  color: green;
}
<div>
  <p><span class="red">red</span></p>
  <div>
    <p><span class="green">green</span></p>
  </div>
</div>

答案 2 :(得分:-1)

如果要对所有后代执行此操作,则可以通过Javascript来实现(如以下所示),如果要应用多种颜色,它将减少很多代码行,但是比CSS的时间慢。根据您的喜好

var colors = ['red', 'green', 'blue', 'orange', 'brown']
var spans = document.querySelectorAll('span');

spans.forEach(function(spanElement) {
  colors.forEach(function(color){
   if(spanElement.closest(`#${color}`)){
     spanElement.style.color=color
   }      
  }) 
})
<div id="red">
  <span>red</span>
  <div id="green">
    <span>green</span>
    <p><span>green</span></p>
  </div>
  <div id="blue">
    <span>blue</span>   
  </div>
  <div id="orange">
    <span>orange</span>   
  </div>
  <div id="brown">
    <span>brown</span>   
  </div>
</div>