Skip to content
On this page

CSS3 新伪类选择器

emmmm,先复习下什么是伪类选择器。在 CSS 中,伪类选择器一般以冒号 : 开头,并接着紧跟着表示状态或者位置的关键字。

例如:

  • :hover
  • :first-child
  • :active

有些伪类选择器,还支持传入特定的参数,用于精确的匹配元素的位置。

例如:

  • :nth-child(odd) 表示匹配所有元素出现的位置为奇数
  • :not(:empty) 表示匹配元素的内容为非空的位置

这些嘛都不是本文要说的内容,只是做个简单的回顾。

本文主要聊聊 CSS3 中的几个新的伪类选择器,分别是 :has():is():where()

:is()

:is() 伪类选择器可以接收一组选择器列表作为参数(参数用逗号分隔),并能够选择列表中任意一个可匹配的元素应用样式规则。这个是非常有用的一个伪类选择器,本人已经在项目中使用该选择器很多次,节省了大量 css 样式代码编写。

来看个例子就能知道为什么如此有用

html
<header>
   <p></p>
</header>
<main>
   <p></p>
</main>
<footer>
   <p></p>
</footer>

在上面这个 html 结构中,如果要选择 header,main 以及 footer 下面的 p 标签,你会如何做?

大多数人在借助预处理器语言(Scss,Less)的情况下,会编写出这样的代码。

scss
header, footer, footer {
    p {
        // 
    }
}

这样写,当然没问题,但是原生的 :is() 选择器能够更优雅实现

css
:is(header, main, footer) p {
    /*  */
}

下面是用 :is() 选择器实现的上面的示例

Lorem ipsum dolor sit amet consectetur adipisicing elit. Incidunt iure ut animi vero a, inventore dolorem in assumenda maxime est eaque vel aspernatur aliquam porro explicabo tenetur vitae ab quis.

Lorem ipsum dolor, sit amet consectetur adipisicing elit. Porro eaque doloremque accusamus molestiae delectus facilis eius, ipsam ratione quibusdam quos, dolor ullam. Non quia, saepe doloremque facere quaerat adipisci mollitia!

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Tempora praesentium ea earum, autem similique deleniti repudiandae ad quae eligendi, atque quaerat in quis maxime minima commodi? Aperiam deserunt voluptatibus porro.

怎么样,看起来是不是很有用呢?

这里的 is() 伪类选择器会匹配选择器列表中的任意一个可匹配的元素并找到该元素的后代元素 p 应用样式规则。

需要,注意的是 :is() 选择器的权重值为参数列表中取权重值最高的那个。

css
:is(#app, .app, main) {
    /* 这个 :is 选择器的权重为 100,因为这个参数列表中,id选择器权重值最高 */
}

警告

:is() 伪类选择器不能接收伪元素作为参数列表。所以这样不行:

css
p:is(::before, ::after) {
    font-size: 10em;
}

说明

在 chrome <= 88 版本 之前,可以使用 :webkit-any() 做向后兼容,这个 :-webkit-any:is() 的非标准化版的实现。

:where()

:where() 选择器的功能和 :is() 一致,唯一的不同在 :where() 权重值永远为 0

:has()

:has() 选择器是一个后起之秀的新伪类选择器,目前兼容性还不够好,且由于刚推出没多久,没有非标准化的版本导致无法向后兼容。

但这不妨碍我们去了解并掌握它。

:has() 能够选择匹配指定后代的祖先元素,这个祖先元素很重要,要知道,我们在编写 CSS 选择器的时候从左往右写,思维习惯就是从祖先元素出发找到与之匹配的后代元素并应用样式。

但是 :has() 选择器能够让我们反过来,从与之匹配的后代元素中为祖先元素应用样式规则。

来看一个例子。

html
<div>
    <p v-if="show"></p>
    <article v-else></article>
</div>

我希望如果 div 的后代元素是 article 时,将 div 变为蓝色,如果后代元素是 p 时,将 div 变为 红色。

在不借助 JS 的情况下,如果没有 :has() 这个还真无法实现,但是好在现在已经有了 :has() 了。

我们只需要:

css
div:has(article) {
    background: blue;
}

div:has(p) {
    background: red;
}

来看这个示例,点击 toggle 将根据 div 是否有匹配的后代元素来应用样式规则。

这里的意思是,如果 div 的后代有 article 元素,则为 div 的背景颜色置为蓝色。如果 div 的后代有 p 元素,则为 div 的背景颜色置为红色。

这个伪类选择器搭配 :not():empty 等组合起来使用会非常强大。

css
/* 表示匹配后代元素 p 元素且内容不为空的 .parent */
.parent:p:not(:empty) {
    padding: 1em;
    border-raidus: .5em;
}

提示

:has() 伪类的优先级计算方法与 :is():not() 相同:以其参数中具体的选择器进行计算。

浏览器兼容性

chromefirefoxsafari
:has()>=105目前仍不支持(113>=15.4
:where()>=88>=111>=14
:is()>=88(不包含 -webkit-any)>=78(不包含 -webkit-any)>=14(不包含 -webkit-any)