【前端小课堂】CSS伪类函数:is和:where

803 阅读3分钟

简述

:is()前身是:match(),在 CSSWG issue #3258 讨论后 :matches() 改名为 :is():is()伪类函数可以大幅度简化复合选择器的复杂度,降低书写选择器出错的风险。

基本用法

:is()伪类函数的参数是一个选择器列表,并选择该列表中任意一个选择器可以选择的元素。 例如:

ul li, ol li  {}

可以简化为

:is(ul, ol) li  {}

为了对比更加直观,继续看一个相对复杂点的例子:

:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6)  {
    color: red;  
}

等价于

section h1, section h2, section h3, section h4, section h5, section h6,
article h1, article h2, article h3, article h4, article h5, article h6, 
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6, 
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6  {  
    color: red;  
}

:is()伪类函数大幅度缩减了选择器列表的字符数,简化了选择器列表的复杂度,降低了书写选择器列表出错的概率

跨浏览器兼容

基于早期的:-webkit-any():matches()伪类函数兼容支持,:is()伪类函数跨浏览器兼容覆盖率很高。下面是caniuse给出的各浏览器的兼容统计,可以参考了解一下。

1631628122855.jpg

详细数据,可查看这里

许多浏览器通过一个更旧的、带前缀的伪类:any()来支持这个功能,包括旧版本的Chrome、Firefox和Safari。这与:is()的工作方式完全相同,只是它需要厂商前缀,不支持复杂的选择器。

CSS兼容

/* 向后兼容的版本:-*-any()*/
:-webkit-any(section, article, aside, nav) h1{
    color: red;  
}

:-moz-any(section, article, aside, nav) h1{
    color: red;  
}

:matches(section, article, aside, nav) h1{
    color: red;  
}

:is(section, article, aside, nav) h1  {
    color: red;  
}

JS语法兼容

如果document.querySelectorAll方法参数是无效选择器,将会报以下异常:

Uncaught DOMException: Failed to execute 'querySelectorAll' on 'Document': 'xxxx' is not a valid selector.

因此,可以借助try{...}catch(e){...},做兼容处理,查看示例

let matchedItems;

try {
  matchedItems = document.querySelectorAll(':is(header, main, footer) p');
} catch(e) {
  try {
    matchedItems = document.querySelectorAll(':-webkit-any(header, main, footer) p');
  } catch(e) {
    try {
      matchedItems = document.querySelectorAll(':-moz-any(header, main, footer) p');
    } catch(e) {
      console.log('Your browser doesn\'t support :is() or :any()');
    }
  }
}

for(let i = 0; i < matchedItems.length; i++) {
  applyHandler(matchedItems[i]);
}

function applyHandler(elem) {
  elem.addEventListener('click', function(e) {
    alert('这是一个包含于' + e.target.parentNode.nodeName + '的段落');
  });
}

有关:any()伪类函数的说明

:any()支持含有一个或者多个类选择器、元素选择器或者伪类选择器,但是不支持组合选择器和伪元素选择器。比如

下面的代码有效

:-moz-any(p.warning.new, p.error, div#topnotice){
    color:red;
}

:-moz-any(:link, :visited).external:-moz-any(:active, :focus){
    color:red;
}

但是,下面代码是无效的

/**组合选择器**/
:-moz-any(div > p){
    color: red;
}
/**伪元素选择器**/
:-moz-any(:first-letter){
    color: red;
}

相关特性

:is()可以避免选择器列表失效

通常选择器列表包含一个或者多个无效选择器,将导致整个选择器列表失效。:is()伪类函数可以避免这个问题。:unsupported是无效选择器,未使用:is()的选择器列表将失效被忽略;而使用:is()会忽略掉无效选择器,其他选择器依然有效。

<section>
  <h1>内容测试</h1>
</section>
<article>
  <h1>内容测试</h1>
</article>

选择器有效,字体颜色为red

:is(section, article,:unsupported) h1{
  color:red;
}

选择器列表整体失效,字体颜色color:red未生效

section h1, article h1,:unsupported{
    color:red;
}

对选择器优先级的影响

:is()的优先级取决于其参数列表中优先级最高的选择器。因此,使用:is()可能会提升选择器的优先级。

例如:

:is(ol, .list, ul) li  {  
    color: red;
}

ol li  { 
    color:green;
}

按照就近原则,ol li字体颜色应该为green,但是:is()参数中有优先级更高的.list,导致:is(ol) li{...}的优先级高于ol li。因此,最终ol li的字体颜色是red

:where()伪类函数

:where()的功能和用法跟:is()完全一致。唯一的区别是,:where()的优先级始终是0。

我们可以验证一下。众所周知,元素选择器的优先级权重是1,因此li{...}的优先级权重是1。如果,li中字体颜色最终呈现为green,说明:where()的影响下选择器的优先级权重始终是0。

:where(ol,.list, ul) li  {  
    color: red;
}

li { 
    color:green;
}

当然,可以对比看一下下面这个例子,加深理解。最终字体颜色为blue

/**优先级权重为0**/
:where(ol,.list, ul) li  {  
    color: red;
}

/**优先级权重为 1+1=2**/
ol li {
    color:blue;
}

/**优先级权重为1**/
li { 
    color:green;
}

参考

css-tricks.com/almanac/sel…

developer.mozilla.org/zh-CN/docs/…

css-tricks.com/almanac/sel…

css-tricks.com/using-the-s…