伪类

CSS 播客 - 015:伪类

假设你有一个电子邮件注册表单,并且你希望电子邮件表单字段在包含无效电子邮件地址时具有红色边框。你该怎么做?你可以使用 :invalid CSS 伪类,它是浏览器提供的许多伪类之一。

伪类允许你根据状态更改和外部因素应用样式。这意味着你的设计可以对用户输入(例如无效的电子邮件地址)做出反应。这些内容在 选择器 模块中介绍,本模块将更详细地介绍它们。

与你可以在 前一个模块 中了解更多的伪元素不同,伪*类*挂钩到元素可能处于的特定*状态*,而不是通常为该元素的各个部分设置样式。

交互状态

以下伪类因用户与你的页面进行交互而应用。

:hover

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 2.

来源

如果用户有鼠标或触控板等指点设备,并且他们将其放置在元素上方,则可以使用 :hover 挂钩到该状态以应用样式。这是一种提示元素可以交互的有用方法。

:active

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

来源

当元素正在被主动交互时(例如单击),在释放单击之前,会触发此状态。如果使用鼠标等指点设备,则此状态是单击开始但尚未释放时。

:focus:focus-within:focus-visible

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

来源

如果一个元素可以接收焦点(例如 <button>),你可以使用 :focus 伪类对该状态做出反应。

如果你的元素的子元素接收到焦点,你也可以使用 :focus-within 做出反应。

可聚焦元素(如按钮)在获得焦点时会显示焦点环,即使在单击时也是如此。在这种情况下,开发人员将应用以下 CSS

button:focus {
    outline: none;
}

此 CSS 在元素获得焦点时删除默认浏览器焦点环,这会给使用键盘导航网页的用户带来无障碍功能问题。如果没有焦点样式,他们在使用 tab 键时将无法跟踪当前焦点所在位置。使用 :focus-visible,你可以在元素通过键盘接收焦点时呈现焦点样式,同时使用 outline: none 规则来防止在指针设备与之交互时出现焦点样式。

button:focus {
    outline: none;
}

button:focus-visible {
    outline: 1px solid black;
}

:target

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.3.

来源

:target 伪类选择具有与 URL 片段匹配的 id 的元素。假设你有以下 HTML

<article id="content">
    …
</article>

当 URL 包含 #content 时,你可以将样式附加到该元素。

#content:target {
    background: yellow;
}

这对于突出显示可能已通过跳过链接专门链接到的区域(例如网站上的主要内容)非常有用。

历史状态

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

来源

:link 伪类可以应用于任何具有尚未访问的 href 值的 <a> 元素。

:visited

你可以使用 :visited 伪类为用户已访问过的链接设置样式。这与 :link 状态相反,但出于 安全原因,你可以使用的 CSS 属性较少。你只能设置 colorbackground-colorborder-coloroutline-color 以及 SVG fillstroke 的颜色。

顺序很重要

如果你定义了 :visited 样式,则可以被具有至少相同特异性的链接伪类覆盖。因此,建议你使用 LVHA 规则以特定顺序使用伪类设置链接样式::link:visited:hover:active

a:link {}
a:visited {}
a:hover {}
a:active {}

表单状态

以下伪类可以选择表单元素,以及这些元素在与其交互期间可能处于的各种状态。

:disabled:enabled

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

来源

如果表单元素(例如 <button>)被浏览器禁用,你可以使用 :disabled 伪类挂钩到该状态。:enabled 伪类可用于相反的状态,尽管表单元素默认情况下也处于 :enabled 状态,因此你可能不会经常使用此伪类。

:checked:indeterminate

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

来源

当支持的表单元素(例如复选框或单选按钮)处于选中状态时,可以使用 :checked 伪类。

:checked 状态是一个二进制(真或假)状态,但复选框确实有一个中间状态,即它们既未选中也未取消选中。这被称为 :indeterminate 状态。

此状态的一个示例是当你有一个“全选”控件来选中组中的所有复选框时。如果用户随后取消选中其中一个复选框,则根复选框将不再表示“全部”选中,因此应将其置于不确定状态。

<progress> 元素也具有可以设置样式的不确定状态。一个常见的用例是为其提供条纹外观,以指示尚不清楚还需要多少。

:placeholder-shown

浏览器支持

  • Chrome: 47.
  • Edge: 79.
  • Firefox: 51.
  • Safari: 9.

来源

如果表单字段具有 placeholder 属性且 没有值,则可以使用 :placeholder-shown 伪类将样式附加到该状态。一旦字段中有内容(无论它是否具有 placeholder),此状态将不再适用。

验证状态

浏览器支持

  • Chrome: 10.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 5.

来源

你可以使用伪类(例如 :valid:invalid:in-range)响应 HTML 表单验证。:valid:invalid 伪类对于诸如具有需要匹配的 pattern 的电子邮件字段之类的上下文很有用,以便使其成为有效字段。可以将此有效值状态显示给用户,帮助他们了解他们可以安全地移动到下一个字段。

如果输入具有 minmax(例如数字输入) 并且 值在这些边界内,则可以使用 :in-range 伪类。

使用 HTML 表单,你可以使用 required 属性确定字段是否为必填字段。:required 伪类将可用于必填字段。可以使用 :optional 伪类选择非必填字段。

按索引、顺序和出现次数选择元素

有一组伪类可以根据项目在文档中的位置选择项目。

:first-child:last-child

浏览器支持

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 3.
  • Safari: 3.1.

来源

如果要查找第一个或最后一个项目,可以使用 :first-child:last-child。这些伪类将返回兄弟元素组中的第一个或最后一个元素。

:only-child

浏览器支持

  • Chrome: 2.
  • Edge: 12.
  • Firefox: 1.5.
  • Safari: 3.1.

来源

你还可以使用 :only-child 伪类选择没有兄弟元素的元素。

:first-of-type:last-of-type

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

来源

你可以选择 :first-of-type:last-of-type,乍一看,它们似乎与 :first-child:last-child 做的事情相同,但请考虑以下 HTML

<div class="my-parent">
    <p>A paragraph</p>
    <div>A div</div>
    <div>Another div</div>
</div>

以及此 CSS

.my-parent div:first-child {
    color: red;
}

没有任何元素会被染成红色,因为第一个子元素是段落而不是 div。:first-of-type 伪类在此上下文中很有用。

.my-parent div:first-of-type {
    color: red;
}

即使第一个 <div> 是第二个子元素,但它仍然是 .my-parent 元素内部的第一个类型,因此使用此规则,它将被染成红色。

:nth-child:nth-of-type

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

来源

你不仅限于第一个和最后一个子元素和类型。:nth-child:nth-of-type 伪类允许你指定位于特定索引处的元素。CSS 选择器中的索引从 1 开始。

你也可以将多个索引传递到这些伪类中。如果你想选择所有偶数元素,可以使用 :nth-child(even)

你还可以创建更复杂的选择器,使用 An+B 微语法 查找以规则间隔排列的项目。

li:nth-child(3n+3) {
    background: yellow;
}

此选择器选择每第三个项目,从项目 3 开始。此表达式中的 n 是索引,从零开始,3 (3n) 是你将该索引乘以的量。

假设你有 7 个 <li> 项目。选择的第一个项目是 3,因为 3n+3 转换为 (3 * 0) + 3。下一个迭代将选择项目 6,因为 n 现在已递增为 1,因此为 (3 * 1) + 3)。此表达式适用于 :nth-child:nth-of-type

你可以在此 nth-child 测试器 或此 数量选择器工具 上试用这种选择器。

:only-of-type

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

来源

最后,你可以使用 :only-of-type 查找兄弟元素组中某种类型的唯一元素。如果你想选择只有一个项目的列表,或者如果你想查找段落中唯一的粗体元素,这将非常有用。

查找空元素

有时识别完全空的元素可能很有用,并且也有一个用于此目的的伪类。

:empty

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

来源

如果元素没有子元素,则 :empty 伪类适用于它们。子元素不仅仅是 HTML 元素或文本节点:它们也可以是空格,当你在调试以下 HTML 并想知道为什么它不适用于 :empty 时,这可能会令人困惑

<div>
</div>

原因是打开和关闭 <div> 之间存在一些空格,因此 empty 将不起作用。

如果你对 HTML 的控制权很小并且想要隐藏空元素(例如 WYSIWYG 内容编辑器),则 :empty 伪类可能很有用。在这里,编辑器添加了一个迷路的空段落。

<article class="post">
 <p>Donec ullamcorper nulla non metus auctor fringilla.</p>
 <p></p>
 <p>Curabitur blandit tempus porttitor.</p>
</article>

使用 :empty,你可以找到它并隐藏它。

.post :empty {
    display: none;
}

查找和排除多个元素

一些伪类可帮助你编写更紧凑的 CSS。

:is()

浏览器支持

  • Chrome: 88.
  • Edge: 88.
  • Firefox: 78.
  • Safari: 14.

来源

如果你想在 .post 元素中查找所有 h2liimg 子元素,你可能会想到编写如下选择器列表

.post h2,
.post li,
.post img {
    
}

使用 :is() 伪类,你可以编写更紧凑的版本

.post :is(h2, li, img) {
    
}

is 伪类不仅比选择器列表更紧凑,而且更宽容。在大多数情况下,如果选择器列表中存在错误或不受支持的选择器,则整个选择器列表将不再起作用。如果 :is 伪类中传递的选择器中存在错误,它将忽略无效的选择器,但使用那些有效的选择器。

:not()

浏览器支持

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

来源

你还可以使用 :not() 伪类排除项目。例如,你可以使用它来设置所有没有 class 属性的链接的样式。

a:not([class]) {
    color: blue;
}

not 伪类还可以帮助你提高无障碍功能。例如,<img> 必须具有 alt,即使它是一个空值,因此你可以编写一个 CSS 规则,为无效图像添加粗红色轮廓

img:not([alt]) {
    outline: 10px red;
}

检查你的理解情况

测试你对伪类的知识

伪类的作用就像动态地将类应用于元素一样,而伪元素则作用于元素本身。

正确
注意在选择器中使用单冒号或双冒号作为关键区分字符
错误
伪元素用于部件,伪类用于状态。

以下哪些是 功能性 伪类?

:is()
🎉
:target
功能性伪类在它们后面有 (),以指示它们接受参数。
:empty
功能性伪类在它们后面有 (),以指示它们接受参数。
:not()
🎉

以下哪些伪类是由于用户交互而产生的?

:hover
🎉
:press
再试一次!
:squeeze
再试一次!
:target
🎉
:focus-within
🎉

以下哪些是 <form> 状态伪类?

:enabled
🎉
:fresh
再试一次!
:indeterminate
🎉
:checked
🎉
:in-range
🎉
:loading
再试一次!
:valid
🎉