继续第一部分的内容,本集将重点介绍被归类为伪类和伪元素的高级CSS选择器,以及每种选择器的实际应用。我们将特别尝试理解nth-child 的语法。
伪类
这是最大的一个类别,也是最依赖上下文的一个类别。
伪类是一些关键词,当它们与元素的选定状态或上下文相匹配时就会被应用。
这大大增加了CSS的功能,并实现了在过去经常被错误地归入JavaScript的功能。
有些选择器是有状态的:
:focus:hover:visited:target:checked
而其他的选择器则与元素的顺序相联系:
:nth-child()/:nth-of-type():first-child/:first-of-type:last-child/:last-of-type:only-child/:only-of-type
然后是非常有用的伪类:not() ,新支持的:is() ,以及随着CSS自定义属性(变量)的支持率上升而出现的:root 伪类。
查看MDN文档,了解可用的伪类的完整列表,包括针对表单输入、
video字幕和语言的可用选项,以及一些目前正在实施的选项。
伪类的实际应用#
斑马纹表行
nth 系列的选择器有无穷的应用。将它们用于任何你想使用基于1的索引出现的重复模式。
一个很好的候选者是表行的斑马纹。
nth-child 选择器可以使用一个整数,用函数符号来定义,或者使用关键字even 或odd 。我们将使用关键字来最有效地产生我们的斑马线规则。
tbody tr:nth-child(odd) {
background-color: #ddd;
}
这将产生以下结果:

应用交替的背景颜色
使用nth-child 的功能符号,我们可以交替使用一系列的背景颜色,并确保图案按照定义的顺序重复,无论存在多少个元素。因此,rebeccapurple,darkcyan,lightskyblue 的模式将按这个顺序重复。
这种工作方式是将颜色的总数--3 --与n 一起定义,它代表从0开始的所有正数,并将与相关数字相乘,在这种情况下,3 。所以就其本身而言,3n 会选择第3项、第6项、第9项,以此类推。它不会选择列表中的第一个,因为3 x 0 = 0 。
对于我们的重复模式,我们希望第一个被选中的项目是我们调色板中的第一个颜色。
因此,我们把这个符号扩展为3n + (integer corresponding to color order) ,因此我们的第一种颜色规则就变成了。
li:nth-child(3n + 1) {
background-color: rebeccapurple;
}
而这将选择每三个元素,从第一个开始:

本质上,这个+ [number] ,转移了起始索引。
为了完成我们的模式,我们定义了以下规则,增加的数字是重复模式中颜色的顺序:
li:nth-child(3n + 2) {
background-color: darkcyan;
}
li:nth-child(3n + 3) {
background-color: lightskyblue;
}
产生以下完成的结果。
删除子元素的额外间距
如果你没有使用以零边距开始所有元素的重置,你可能会遇到排版元素产生额外的不需要的边距,使视觉容器内的间距不平衡。
伪类并不总是需要直接附加到一个元素上,这意味着我们可以做下面的规则,它附加到任何元素,恰好是任何父元素的最后一个孩子,并确保它没有margin-bottom 。
:last-child {
margin-bottom: 0;
}
从选择器中排除元素
仔细应用:not() ,对于排除被选择的元素非常有用。
我们在属性选择器部分探讨了:not() 的一些用途,特别是a:not([class]) ,用于针对没有应用其他类的链接。
:not() 是在实用框架或设计系统中使用的极好的方法,以提高对有可能应用于任何东西的类的特异性,对于这些类,在某些组合上存在着已知问题。
对有链接的类排除它的一个扩展例子是,当你调整文本的对比度时,可能是在黑暗模式的背景下,并希望将对比度调整也应用于文本链接。
/* Non dark mode application */
a:not([class]) {
color: blue;
}
/* Update text color for dark mode */
.dark-mode {
color: #fff;
}
/* Extend the color update to links via `inherit` */
.dark-mode a:not([class]) {
color: inherit;
}
你也可以连锁:not() 选择器,所以也许你想为表单字段输入创建一个规则,但不包括某些类型。
input:not([type="hidden"]):not([type="radio"]):not([type="checkbox"])
也可以在:not() ,包括其他伪选择器,如排除按钮的:disabled 状态。
button: not(: disabled);
这允许你通过先定义一个重置的button 样式来获得更整洁的规则,然后只对非禁用的按钮应用颜色样式、边框等,而不是在以后删除这些样式用于button:disabled 。
有效地选择元素组
新支持的 :is() 伪类。
"......接受一个选择器列表作为其参数,并选择任何可以被该列表中的一个选择器选择的元素。" -MDN docs on
:is()
这可以产生很大的影响的一种方式是更紧凑地选择排版元素,如:
:is(h1, h2, h3, h4) ;
或者更简洁地确定布局样式的范围,如:
:is(header, main, footer) ;
我们甚至可以将:is() 与:not() ,并真正地精简我们的选择器,在这种情况下,选择不是标题的元素。
:not(:is(h1,h2,h3,h4))
要想了解这个选择器的背景,请查看ModernCSS配套项目SmolCSS.dev中的Smol Composable Card组件。
在不久的将来,如果你想开始使用这个选择器,你至少要包括webkit 前缀版本。由于浏览器在使用选择器时的一个怪癖,你需要把它作为一个独立的规则,与is() ,以避免浏览器把这两个规则都扔掉。
:-webkit-any(header, main, footer) ;
为当前锚定链接元素设置样式
当一个元素是锚定链接(文档片段标识符)的目标时--https://url.com/#anchor-here ,你可以使用:target 。
我的项目11ty.Rocks依赖于锚链接,例如可以看到访问这个链接的CSS Houdini Worklet Generator。
:target 伪类应该放在包含id 属性的元素上。然而,你可以用下级选择器来影响嵌套元素--也许你想给article:target h2 一个更大的尺寸或类似的东西。
利用:target ,我通过与伪元素::before 结合,增加了一点额外的信息,以帮助向访问者表明他们被提供的链接的项目,显示如下("你要找的是我...")。

额外的提示:通过使用scroll-margin-top: 2em; (或其他你选择的值),确保在滚动时在元素顶部之前有一点间隔。这应该被认为是一个渐进式的增强,请务必查看浏览器对scroll-margin-top 的支持。
视觉上显示已访问的档案链接
:visited 伪类是非常独特的,因为它有可能在用户的隐私方面被利用。为了解决这个问题,浏览器制造商已经限制了哪些CSS样式允许使用:visited 。
Una Kravets有一个更深入的参考资料,探讨如何创建有用的:visited 样式,但这里是我为Style Stage的访问者提供的简化版本,以跟踪他们已经查看过的样式。
一个关键的问题是,通过:visited 应用的样式将总是使用父级的alpha通道--这意味着,你不能使用rgba 来从不可见到可见,你必须改变整个颜色值。
所以,为了隐藏初始状态,你需要能够使用一个纯色,比如说页面背景色。
此外,为了无障碍性,如果是一个图标或表情符号,可能不希望伪元素内容被读出,因为我们不能为content 值提供一个无障碍的名称。在伪元素内容是否被读出方面,辅助技术之间存在不一致,所以我们可以尝试使用aria-hidden="true" ,确保它被忽略。
那么,我们的第一步是在链接中添加一个跨度,这就是我们最终要应用:visited 样式的地方:
<a href="#">Article Title <span aria-hidden="true"></span></a>
默认样式(非访问)添加了伪元素,并使其颜色与页面背景相同,以在视觉上隐藏它:
a span[aria-hidden]::after {
content: "✔";
color: var(--color-background);
}
然后,当链接被访问后,我们更新颜色,使其可见:
a:visited span[aria-hidden]::after {
color: var(--color-primary);
}
先进的交互方式:focus-within
一个即将出现的伪类是:focus-within ,它有一个polyfill,但除此之外,应该谨慎使用,或作为一个渐进的增强。
:focus-withinCSS伪类代表一个已经收到焦点的元素或包含一个已经收到焦点的元素。换句话说,它代表一个本身被:focus伪类匹配的元素,或者有一个被:focus匹配的后裔。
伪元素#
伪元素允许你对所选元素的一个特定部分进行样式设计。它们的应用差别很大,(目前)最好的支持是以下几种:
::after::before::first-letter::first-line::selection
伪元素的实际应用
额外的视觉元素的造型优势
::before 和::after 伪元素创建了一个额外的元素,在视觉上似乎是DOM的一部分,但并不是真正的HTML DOM的一部分。它们和任何真正的DOM元素一样,都是完全可以被样式化的。
我已经用这些元素做了各种点缀。由于它们的行为就像真正的元素,在使用flexbox或CSS网格布局时,它们被计算为子元素,这大大增加了它们在我工具箱中的功能。
使用::before 和::after 的几个关键概念。
- 需要
content属性,然后才能使其可见,但这个属性可以设置为一个空白字符串 -content: ""; - 关键的文本内容不应包括在
content值中,因为辅助技术对它的访问是不一致的 - 除非另有定位,否则
::before将在主元素内容之前显示,而::after将在其之后显示。
下面是一个只应用了一点样式的默认行为的演示:

请注意,它们默认情况下就像内联元素,对于较长的内容也遵循包装行为:

这里是通过单一的调整将display: flex ,以增加段落:

这里是将其替换为display: grid 。

::before 和::after 元素是添加简单、一致的排版装饰的快速方法,在这个 CodePen 演示中可以看到其中一些。
作者:Stephanie Eckles (@5t3ph)
你抓住了表情符号中的技巧吗?
我们可以通过attr() 函数检索元素上的任何属性的值,以便在content 属性中使用。
/*
<h2 class="emoji" data-emoji="😍">
*/
.emoji::before {
content: attr(data-emoji);
}
这里有一个要点,就是如何用这个同样的思路在伪元素中显示元素id 和class 的值。你也可以在推特上分享这个提示 >
强调文章的线索
lede"(读作 "引子")是一个新闻术语,指的是新闻文章中的第一段,目的是对文章的关键点进行总结(你可能听说过 "不要埋没引子 "这句话)。
我们可以将:first-of-type 的伪类与:first-line 的伪元素结合起来,以强调段落副本的第一行。有趣的是,这是动态的,会随着视口大小的变化而变化。
article p:first-of-type:first-line {
font-weight: bold;
font-size: 1.1em;
color: darkcyan;
}
产生以下固有的响应性结果:

确保文本选择的可访问对比度
一个经常被忽略的样式是文本选择,尽管它是我们许多人每天多次参与的互动。
虽然浏览器试图处理这个事件的样式,但有可能失去对比度。我在为ModernCSS.dev设计样式时遇到了这种情况,因为使用的是深色的主题。
为了解决这个问题,我们可以使用::selection 伪元素来提供一个自定义文本颜色和背景颜色:
::selection {
background: yellow;
color: black;
}