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

Posted

技术标签:

【中文标题】可以重复类型选择器以增加特异性吗?【英文标题】:Can type selectors be repeated to increase specificity? 【发布时间】:2015-04-02 16:51:15 【问题描述】:

spec 声明关于计算 CSS 特异性:(我的粗体字)

注意:允许重复出现相同的简单选择器,并且 确实增加特异性。

例如,.class.class 的特异性是 .class 的两倍 - DEMO

但是,关于术语“简单选择器”the spec 有这样的说法:(我的粗体字)

简单的选择器可以是类型选择器或通用选择器 紧随其后的是零个或多个属性选择器,ID 选择器或伪类,以任意顺序排列。

因此,既然规范说允许重复出现相同的简单选择器 - 这意味着您也可以重复 type selectors。

很明显这样的事情是行不通的:h1h1 ,

所以我尝试了这个:h1[]h1[] - 这也不起作用,

所以我想知道是否有办法做到这一点?

【问题讨论】:

我感觉这实际上是规范编写方式的错误.. 我不得不同意,我想我以前从未见过这样的事情。我可能不得不把它弄得一团糟并对其进行测试,但这似乎不太可能是正确的。 【参考方案1】:

可以使用类型选择器来增加选择器的特异性,但不是常规的。原因在下面解释,但对于那些只是在寻找替代品的人来说,有两个。您可以在单个复合选择器中链接包含类型选择器的 :not() 伪类:

h1                       /* 1 type  -> specificity = 0-0-1 */
h1:not(_)                /* 2 types -> specificity = 0-0-2 */
h1:not(_):not(_)         /* 3 types -> specificity = 0-0-3 */
h1:not(_):not(_):not(_)  /* 4 types -> specificity = 0-0-4 */

或者,如果您需要支持不支持 :not() 的旧版浏览器,您可以在复杂选择器的开头添加冗余类型选择器,例如 htmlbody,尽管您的限制要大得多在这种情况下,您可能无法考虑所有元素:

h1                 /* 1 type  -> specificity = 0-0-1 */
body h1            /* 2 types -> specificity = 0-0-2 */
html body h1       /* 3 types -> specificity = 0-0-3 */
html body tr > td  /* 4 types -> specificity = 0-0-4, assumes every td is a child of tr */

不用说,这些被认为是特异性黑客;与所有其他 CSS hack 一样,尽量少用。


复合选择器最多只能有一个类型选择器在所有其他简单选择器之前。来自Selectors 3(称之为简单选择器序列):

简单选择器序列是一个简单选择器链,没有被组合符分隔。它总是以类型选择器或通用选择器开头。序列中不允许有其他类型选择器或通用选择器。

还有Selectors 4:

复合选择器 是一系列简单的选择器,没有被组合符分隔。如果它包含类型选择器或通用选择器,则该选择器在序列中排在第一位。序列中只允许使用一种类型选择器或通用选择器。

只有类型和通用选择器受此规则约束;您可以组合并重复其他简单的选择器以增加特异性。也许规范可以在计算特异性部分提醒读者这一点,但我认为这不是绝对必要的。

这条规则的原因从未明确说明,但很容易推断:

请记住,类型选择器仅由一个标识符组成,例如h1。这与其他简单的选择器不同,它们在语法中具有自己的区分符号,例如 ID (#)、类 (.)、伪类 (:) 或属性选择器 (@ 987654334@)。如果没有单独解析它们的方法,您将无法拥有多个连续的类型选择器。

即使您可以链接类型选择器,例如,如果您在它们之间有另一个简单的选择器,那么唯一可能的用途就是作为特异性黑客,如问题中所述,意味着只有在所有类型选择器都相同的情况下才能使用它;没有其他类型选择器的组合可以工作。

这是因为选择器假定文档语言将每个元素定义为恰好具有一种元素类型。例如,在 HTML 中,h1 始终是 h1;它永远不能是任何其他类型的元素。要求既是 h1 又是 p 的元素的复合选择器永远无法匹配任何内容,出于同样的原因,[type=text][type=password] 之类的东西永远无法匹配不支持重复属性的文档语言中的任何内容。

但是,考虑到以上几点,仍然可以创建一个包含多个类型选择器的复合选择器——通过使用 :not() 伪类:

:not() 伪类的特异性等于它的参数。伪类本身不计算在内。这在第一个链接中提到。这意味着:not(h1) 的特异性等同于h1 — 一种类型选择器。

由于一个元素只能是一种类型,这意味着:not() 与任何其他类型选择器都可以保证匹配。

由于复合选择器可能包含任意数量的伪类,因此您可以根据需要多次重复否定,即使所有否定都使用相同的类型选择器。

1234563满足类型选择器的选择器语法。类型选择器只包含一个 CSS 标识符,因此任何 CSS 标识符都是公平的游戏。包括_

【讨论】:

感谢您提供如此详细的答案!只是好奇:为什么你会认为选择器body h1 是一个黑客?我还想到了另一种可能的增加特异性的方法:类似h1:nth-child(n) - 但实际上看起来更hacky @Danield:因为没有真正的理由你应该在那里有body选择器,因为你通常可以假设h1总是在body中。每当我为了增加特异性而添加选择器时,我都会觉得有点脏:) @BoltClock,你知道h1:not(i) 的浏览器限制吗?没有找到,但也不能使用 caniuse 。 :) @Andrei Gheorghiu:没有已知的限制。我敢肯定,您不必担心在过去 10 年制造的任何浏览器中都无法使用(IE8 除外,其中 :not() 无论如何都无法使用):)

以上是关于可以重复类型选择器以增加特异性吗?的主要内容,如果未能解决你的问题,请参考以下文章

CSS 类重复以增加特异性

为啥禁用 CSS 规则 [重复]

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

:not 伪类是不是增加了选择器的特异性?

了解特异性:在不使用 !important 的情况下实现所需的选择器结果 [重复]

格式化日期选择器以发布到 MySQL DB