:where() 和 :is() 之间有什么区别?

leo*_*ess 9 css css-selectors

CSS 最近添加了伪类:where():is()但我不明白何时使用哪个。两者都可用于选择多个元素。这是一个片段,其中两个伪类都实现了相同的效果:

span {
  display: inline-block;
  height: 100px;
  width: 100px;
  background-color: grey;
  margin-bottom: 10px;
}

:is(.span1-1, .span1-2):hover {
  background-color: firebrick;
}

:where(.span2-1, .span2-2):hover {
  background-color: teal;
}
Run Code Online (Sandbox Code Playgroud)
<span class="span1-1"></span>
<span class="span1-2"></span>
<br>
<span class="span2-1"></span>
<span class="span2-2"></span>
Run Code Online (Sandbox Code Playgroud)

有人可以举一个他们行为不同的例子吗?

Bol*_*ock 5

如前所述,区别在于特异性。MDN上提到了这一点,但由于某种原因没有突出显示。另一方面,规范对此更加明确:

\n
\n

4.4. 特异性调整伪类::where()

\n

特异性调整伪类:where()是一个函数伪类,其语法和功能与 相同:is()。与 不同的是:is():where伪类及其任何参数都不会影响选择器\xe2\x80\x94 的特异性,它的特异性始终为零。

\n
\n

有哪些用例?嗯,在你给出的例子中,它并不是很有用。您没有任何需要匹配或不覆盖特异性的竞争选择器。您有一个基本span规则,以及一个:hover自然地覆盖它的规则(即仅通过特异性如何工作以及特异性最初设计的目的)。如果您不需要考虑任何特殊或例外的样式,那么使用:is()或并不重要:where()

\n

:where()当您有更通用的规则,其中包含不必要的特定选择器,并且这些规则需要被具有不太特定选择器的更专门规则覆盖时,它就会变得有用。MDN 和规范都包含一个(非常)常见用例的示例 \xe2\x80\x94 我不想简单地重复MDN 上的内容,所以这里是规范中的一个:

\n
\n

下面是一个常见的例子,其中特异性启发式未能满足作者的期望:

\n
a:not(:hover) {\n  text-decoration: none;\n}\n\nnav a {\n  /* Has no effect */\n  text-decoration: underline;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然而,:where()作者可以通过使用来明确声明他们的意图:

\n
a:where(:not(:hover)) {\n  text-decoration: none;\n}\n\nnav a {\n  /* Works now! */\n  text-decoration: underline;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

与 MDN 不同,该规范并没有真正用英语解释这个用例,所以我会解释。这里的“作者期望”是nav aCSS 规则(我称之为专门规则)将覆盖a:not(:hover)规则(我称之为一般规则)。表面上看,这并没有发生。

\n

由于:hover伪类比类型选择器更具体,因此任何仅具有类型选择器的规则都无法覆盖a:not(:hover)适用于任何a未悬停的规则的一般规则。传统上,您需要通过复制有问题的位来匹配的特异性,大多数 na\xc3\xafvely:a:not(:hover)

\n
a:not(:hover) {\n  text-decoration: none;\n}\n\nnav a, nav a:not(:hover) {\n  /* Works, but not ideal, to say the least */\n  text-decoration: underline;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

或者,通过添加选择器来增加特异性而不影响匹配

\n
a:not(:hover) {\n  text-decoration: none;\n}\n\nnav a:nth-child(n) {\n  /* Works, but not ideal either */\n  text-decoration: underline;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

(或者a:any-link,在链接的情况下)

\n

所做:where()的就是允许您完全删除添加的特殊性:hover,从而更容易地为某些a元素覆盖此规则,例如,通过确保aa 中的元素nav始终带有下划线,无论光标是否位于它们上方(因为nav a更具体)不仅仅是a)。

\n

不同寻常的是,因为它降低了选择器的特异性,所以您通常会使用:where()需要重写的选择器,而不是重写选择器。另一方面,您可以:is()简单地使用来减少 CSS 规则中的选择器重复,例如通过更改

\n
.span1-1:hover, .span1-2:hover\n
Run Code Online (Sandbox Code Playgroud)\n

\n
:is(.span1-1, .span1-2):hover\n
Run Code Online (Sandbox Code Playgroud)\n

同时保留特异性(尽管请注意,:is()一旦您将具有不同特异性量的选择器分组,其工作方式就会有所不同)。

\n

这意味着虽然与:where()具有类似的语法:is(),但实际上它们是具有不同用例的两个不同的伪类。尽管如此,它们的用例确实有部分重叠。例如,您可能需要在一般规则中减少选择器重复,这意味着使用:is(),但您更愿意:where()同时减少特异性。由于将单个选择器应用于多个选择器很有用:where(),因此允许它接受选择器列表使得您不必编写:where(:is(selector-list)). 这一原则适用于许多其他新的伪类,例如:host():host-context():has(),以及级别 4 :not()

\n

  • :is() 和 :where() 很荣幸成为我第一次口头 CSS 演示的主题,我对此感到非常自豪,因为我由于残疾而很少说话,但是我只简要介绍了具体内容,而没有实际的内容例如([带有时间戳的链接](https://www.youtube.com/watch?v=qGC683FOIpg#t=18m20s)),所以这个答案旨在取代我演讲的那部分。 (3认同)