嵌套 CSS 选择器而不增加特异性

Posted

技术标签:

【中文标题】嵌套 CSS 选择器而不增加特异性【英文标题】:Nesting CSS selectors without increasing specificity 【发布时间】:2016-03-29 19:19:35 【问题描述】:

让我们来看看这三个选择器,从高到低排序:

.special-section p  
.weird-font         
p                   

许多 CSS 专家建议不要像在第一个选择器 .special-section p 中那样进行嵌套,因为它的特异性足够高,以至于您无法使用像 .weird-font 这样的简单类来覆盖它。我想找到一种方法来仍然像.special-section p 那样实现嵌套,但不增加特异性。像这样的:

 .weird-font  
 .special-section p /* with hack to decrease specificity */  
 p  

用例:

使用像p 这样的简单选择器为排版和文档范围应用默认值是非常安全的。但是,我想更改特定部分的这些默认值,类似于.special-section p,而不必使用黑客来增加选择器的特异性,例如.weird-font。我宁愿使用 hack 来降低 .special-section p 的特异性,也不愿使用 hack 来增加 .weird-font 的特异性。有没有办法做到这一点?

【问题讨论】:

!important 的问题是只有一层覆盖。如果你制作了一个更具体的选择器,你可以用一个更具体的选择器再次覆盖它。使用!important 后,你别无选择。 添加类然后由它们选择不是一个技巧;这是选择元素的定义方式。如果您有一些示例标记,则用例可能会更清楚。 @TylerH:这不是 OP 所指的。您真的不需要示例标记来推断在示例 CSS 中,p 和 .weird-font 指的是同一个元素。 @BoltClock 我不同意;我完全不清楚 OP 的标记会是什么样子。即使通过巨大的努力,我们可以做出一个假设(所有答案都是如此),但通过一个简单的标记示例,它会变得更清晰、更容易理解(因此对其他人有帮助)。此外,如果我们知道标记,我们可以提供一种潜在的替代方法来实现 OP 的目标。例如,接受的答案与 OP 想要的完全相反(它在他想要避免增加特异性的地方增加了特异性)。 @TylerH:我不否认总有改进的余地,但考虑到 only 的情况,做出这样的假设并不需要“很大的努力”当两个选择器都引用同一个元素时,甚至适用于特殊性。接受的答案和我自己的建议都建议增加而不是减少它,因为你 can't 减少它,并且对于 OP 的问题没有任何其他解决方案不依赖于标记(而且,显然,OP 对这样的解决方案也不是很感兴趣,这也是 fine)。 【参考方案1】:

您不能降低特异性,但可以为异常添加更具体的选择器。

.weird-font, /* Normal weird font */
.special-section p.weird-font /* Override for special section */ 
   

但正如您所见,它是一个滑动比例。所以那些大师可能是对的。如果您要删除.special-section p,而是给这些P 自己的选择器.special-section-para 或其他东西,那么您就不会有这个问题。

但就个人而言,我不介意时不时地添加一个像上面那样的例外。我认为整个特殊性都是为了这个目的,如果你需要一个更具体的选择器来设置样式,对我来说这似乎是正确的做法。

一个常见的解决方案是使用!important。 !important 的问题在于只有一层覆盖。如果你制作了一个更具体的选择器,你可以用一个更具体的选择器再次覆盖它。使用 !important 后,您将别无选择。更重要的是,使用!important 可能会干扰用户为了提高可读性而可能拥有的特殊样式表。出于这个原因,我从不在这种情况下使用!important

但话又说回来,我不认为自己是 CSS 大师。 ;)

【讨论】:

【参考方案2】:

作为一名 CSS 专家,我很遗憾放弃选择器必须提供的所有内容,以避免出现特殊性问题。这并不是说我不相信特异性机制有缺陷,但肯定有不那么引人注目的解决方法。

首先:不,您不能降低选择器的特异性。选择器不提供任何具有负特异性水平的特征,这些特征会以这种方式降低特异性。您可以使用的最低值是*,它具有 特异性(即它不会使复杂的选择器变得或多或少地具有特定性)。

所以你在选择器级别上唯一的办法就是增加它。不使用 hack 是否可以做到这一点取决于您对“hack”的定义。

以下是我认为的 hack,因为它使用了一个语法上合法但语义上无意义的选择器,例如 :not(_),它没有明显的目的,只是将类型选择器的特殊性添加到复杂选择器(即远非显而易见,尤其是外行):

.special-section p  
.weird-font, :not(_).weird-font  

以下内容不是我认为是 hack,因为这是你通常会做的事情。几乎唯一的“问题”是它明显重复了单独的类选择器:

.special-section p  
.weird-font, .special-section p.weird-font  

如果您为了提高特异性而将任何类型的无关选择器视为 hack(这是一个完全合理的 POV,请不要误会),那么 不是 hack 的下一个最好的事情是!important.

就个人而言,我会选择一种特异性破解。 !important 有,咳咳,重要的影响,不附带特异性黑客 - 请记住 !important and specificity have different semantics。例如,您不能使用内联样式或 javascript 覆盖 !important 声明,除非它们也被标记为重要。1


1事实上,这是我对 Lea Verou 的回应,当时她有一个 discussion on Twitter 与 !important 相比的特异性黑客攻击。

【讨论】:

在旁注中,我是唯一一个发现 Twitter 上的讨论无法阅读的人吗?例如,在您链接的讨论中,我可以看到@LeaVerou 回复您说“好点”,但我看不到您最初说的是什么! imgur.com/lUzfW7g @Flimm:哈,这就是为什么我说我对她的回应就是我的回答中给出的 :) 不是你——我将我的帐户设为私有是因为我停止使用 Twitter,但我仍然收到垃圾邮件通知.不好玩:( AFAIK 你不能用任何类型的 CSS 覆盖 JavaScript 插入的 !important 属性。你需要更多的 JavaScript 才能做到这一点。 @TylerH:是的 - 我专门指的是 CSS 级别的 !important 声明。 @BoltClock 啊,“或 JavaScript”位让我失望 :-)【参考方案3】:

如今,在 2018 年,这已接近可能。

首先,CSS4 将有一种方法允许您创建更具体的选择器而不增加特异性:

:where(.special-section) p 
    color: red;

这会将.special-section 中的段落颜色设置为红色,但具有001 的特异性(即与普通p 选择器具有相同的特异性)。

spec 仍然称这个特殊的伪类为:something(),但chances are it's going to be called :where()。 (旁注:我真的want这被称为“蜜獾选择器”)。

但这仍是未来。

然而,如果您不再需要支持 IE(或者对不太完美的回退感到满意),实际上有一种方法可以实现这一点今天 ),即使用custom properties aka CSS 变量。

所以你想要这个:

.special-section p  color: red; 
.weird-font         color: magenta; 
p                   color: green; 

但第一部分的特异性低于任何包含类的选择器。你可以这样做:

.special-section p  --low-specificity-color: red; 
.weird-font         color: magenta; 
p                   color: var(--low-specificity-color, green); 

如果你在现代浏览器中运行下面的 sn-p,你应该注意到第二段是红色的,因为它在一个特殊的部分,但第三段是洋红色的,因为它是 .weird-font -- 即使@ 987654333@ 具有 010 特异性,.special-section p 具有 011。

.special-section p  --low-specificity-color: red; 
.weird-font         color: magenta; 
p                   color: var(--low-specificity-color, green); 
<p>This is a paragraph.</p>

<section class="special-section">
   <p>This is a paragraph inside a special section.</p>
   <p class="weird-font">This is a paragraph with a weird font inside a special section.</p>
</section>

   <p class="weird-font">This is a paragraph with a weird font.</p>

   <div class="weird-font">This is a div with a weird font.</div>

这是可行的,因为虽然 --low-specificity-color 被更改为 011 特异性,但它仅应用为 001 特异性。

【讨论】:

:something(或任何名称)现在是我在科技领域期待的事情的首位! 顺便说一下,为什么是“蜜獾选择器”。我知道它与!important 的相反之处,但我没有得到链接。【参考方案4】:

我喜欢当前需要尽可能具体。我确实喜欢为将来的 CSS 更改留出空间,所以不要为了它而尽可能具体,例如:

.great-grandfather .grandfather .father .child  

如果必须,我当然会。但是以上面的例子为例,如果我想为使用此类的特定元素覆盖 .child,其样式可能如下所示:

.child 
   color: black;

如果可能的话,我会去上面的一位家长覆盖它:

.father .child 
   color: white;

再往下说,如果特定页面上的元素使用.child 类,在这种情况下我需要同时覆盖.father .child,我将再上一层:

.grandfather .father .child 
   color: red;

这样做可以确保您不需要使用!important... 我尽可能避免像瘟疫一样!

【讨论】:

那么有没有办法实现与.parent child选择器相同的效果,但特异性较低?

以上是关于嵌套 CSS 选择器而不增加特异性的主要内容,如果未能解决你的问题,请参考以下文章

可以重复类型选择器以增加特异性吗?

在 iOS 中显示保存文件文档选择器而不提供本地文件 url

#id#id :重复出现相同的简单选择器应该会增加特异性,但对于 IE9 中的 ID 不会

CSS 类重复以增加特异性

了解 CSS 选择器优先级/特异性

CSS选择器级联/特异性未按预期工作