本篇文章收集了几个工作或学习时用到的,好用但是并不常见的 css 伪类选择器,在此做个分享。今后遇到了别的类似选择器,会持续更新~
:has()
在 css 中,如果想根据父元素来选择子元素,我们可以使用 :nth-child() 这样的伪类选择器。如果想根据子元素来选择父元素时,目前并没有个 :parent() 这样的选择器,但是可以使用 :has() 来实现我们的目的。
案例
举个例子,我在一个后台项目中大量的使用了 element ui 的 Table 表格组件 ,几乎每个表格都会有子元素为按钮(button)的操作列,我想统一地设置这些按钮的父元素的样式为 display: flex;,然后通过 gap 属性让存在多个按钮时,每个按钮之间能保持间距,并且通过 flex-wrap: wrap; 使得当按钮过多的时候还能自动换行。
通过浏览器查看 Table 表格组件的元素,可以看到表格的每一个包含数据的单元格 <td> 都有个类名 el-table__cell,它还有个子元素 —— <div class="cell"> —— 我们自己定义的表格内容就会包裹在里面:
也就是说我们需要找到子元素中有 button 的 .cell,然后给它设置样式,此时就用到了 :has():
.el-table__cell > .cell:has(button) {
display: flex;
flex-wrap: wrap;
gap: 10px;
* {
margin-left: 0 !important;
margin-right: 0 !important;
}
}
.el-table__cell > .cell:has(button) 的意思就是找到 .cell,它紧挨着的父元素是 .el-table__cell,并且它的子元素中有 button。呈现的效果如下:
传递给 :has() 的值是一个可容错相对选择器列表,也就是可以有多个选择器,彼此用 , 分割,且当有某个选择器无效时会被直接忽略,不影响其它选择器的正常使用。比如有下面 4 个元素:
<p>我是p1</p>
<div>我是div1</div>
<div>我是div2</div>
<p>我是p2</p>
<div>我是div3</div>
想找到同一个父级元素下的在 p 元素前面的所有 div,让它们的字体颜色变红:
div:has(~ p) {
color: red;
}
效果如下:
兼容性
请注意 :has 的兼容性:
在微信小程序中是不兼容的,我一般只在后台项目中使用。
:is() 与 :where()
案例
在实际项目中我还没使用过 :is() 与 :where(),就先举个如下的例子:
<div class="d1">
<span>你好</span>
</div>
<div class="d2">
<span>掘金</span>
</div>
<div class="d3">
<span>周末愉快</span>
</div>
假设有 3 个 div,我想让 .d1 和 .d2 里的 span 字体颜色为红色,我们可以这样写:
/* 代码片段 1 */
.d1 span,
.d2 span {
color: red;
}
也可以使用 :is() 或 :where() 使得代码看起来更紧凑:
:is(.d1, .d2) span {
color: red;
}
/* 或者 */
:where(.d1, .d2) span {
color: red;
}
:is() 或 :where() 接收的参数为容错选择器列表,这就意味着即使我们传递的某个选择器无效甚至是错误的,比如像下面这样 :hover 少写了一个 r,也只是忽略掉该不正确的选择器而不会影响其它选择器:
:is(.d1:hove, .d2) span {
color: red;
}
效果如下:
但如果是代码片段 1 那样的写法:
.d1:hove span,
.d2 span {
color: red;
}
当写错一个选择器,整个选择器列表都会失效:
:is() 与 :where() 的区别
:is() 与 :where() 大部分情况下使用的效果都相同,区别在于优先级。:is() 会选择其参数中优先级别最高的那个选择器的权重作为自己的权重,而 :where() 的优先级为 0。所以如果 css 样式如下:
.d1 span,
.d2 span {
color: red;
}
:is(.d1) span {
color: green;
}
:where(.d2) span {
color: yellow;
}
最后呈现的效果如下:
因为 :is(.d1) span 的权重与 .d1 span 相同,:is(.d1) span 写在后面,故优先级更高,"你好" 便是绿色;:where(.d2) span 的权重相当于一个单独的 span,低于 .d2 span,所以 "掘金" 是红色。
兼容性
:is() 与 :where() 的兼容性比 :has() 更好,现代浏览器基本上都可以使用。
:empty
:empty 用于选择不包含任何子元素的元素。
案例
在使用原生语法开发微信小程序时,组件的插槽没有提供类似于 vue 中的默认值功能。想实现插槽默认内容的功能,我们可以在定义子组件时,给 <slot> 包裹一个 <view>,添加类名为 slot-wrap,然后紧接着定义一个类名为 slot-default 的 <view> 来声明插槽的默认内容:
<view>
<view>我是子组件</view>
<view class="slot-wrap">
<slot>默认内容,小程序中不生效</slot>
</view>
<view class="slot-default">默认内容</view>
</view>
在组件的样式文件中,就可以先让 .slot-default 默认不显示,然后在 .slot-wrap:empty 即插槽无子元素时,也就是使用组件时没有传入插槽内容的时候,让 .slot-default 显示:
.slot-default {
display: none;
}
.slot-wrap:empty+.slot-default {
display: block;
}
兼容性
现代浏览器基本上都可以使用。
