CSS 播客 - 015:伪类
假设您有一个电子邮件注册表单,并且希望电子邮件表单字段在包含无效电子邮件地址时显示红色边框。 如何实现? 您可以使用 :invalid
CSS 伪类,它是浏览器提供的众多伪类之一。
借助伪类,您可以根据状态变化和外部因素应用样式。 这意味着您的设计可以对用户输入(例如无效的电子邮件地址)做出反应。 选择器模块中介绍了这些内容,本模块将更详细地介绍这些内容。
与伪元素(您可以在上一个模块中详细了解)不同,伪类会挂钩到元素可能处于的特定状态,而不是对该元素的各个部分进行常规样式设置。
互动状态
以下伪类因用户与网页的互动而适用。
:hover
如果用户有鼠标或触控板等指控设备,并且将该设备放置在某个元素上,您可以使用 :hover
挂钩到该状态以应用样式。这是一种有用的方式,可提示用户某个元素可以互动。
:active
当元素正处于互动状态(例如点击)时,但在点击释放之前,系统会触发此状态。 如果使用鼠标等指控设备,则此状态表示点击开始但尚未释放。
:focus
、:focus-within
和:focus-visible
如果某个元素(例如 <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
:target
伪类用于选择具有与网址 fragment 匹配的 id
的元素。假设您有以下 HTML:
<article id="content"> <!-- ... --> </article>
当网址包含 #content
时,您可以将样式附加到该元素。
#content:target { background: yellow; }
这有助于突出显示可能已通过跳过链接专门链接到的区域,例如网站上的主要内容。
历史状态
:link
:link
伪类可应用于任何具有尚未访问的 href
值的 <a>
元素。
:visited
您可以使用 :visited
伪类设置用户已访问过的链接的样式。这与 :link
的状态相反,但出于安全考虑,您可使用的 CSS 属性较少。您只能设置 color
、background-color
、border-color
、outline-color
以及 SVG fill
和 stroke
的颜色。
顺序很重要
如果您定义了 :visited
样式,则至少具有相同特异性的链接伪类可以替换该样式。因此,建议您使用 LVHA 规则来设置伪类链接的样式,并按特定顺序排列::link
、:visited
、:hover
、:active
。
a:link {} a:visited {} a:hover {} a:active {}
表单状态
以下伪类可以选择表单元素,这些元素在与用户互动时可能处于各种状态。
:disabled
和:enabled
如果表单元素(例如 <button>
)被浏览器停用,您可以使用 :disabled
伪类挂钩到该状态。 :enabled
伪类适用于相反的状态,不过表单元素默认也是 :enabled
,因此您可能不会用到此伪类。
:checked
和:indeterminate
当支持的表单元素(例如复选框或单选按钮)处于选中状态时,可以使用 :checked
伪类。
:checked
状态是二元(true 或 false)状态,但复选框在既未选中也未取消选中时,确实存在中间状态。这称为 :indeterminate
状态。
例如,当您有一个“全选”控件来选中一组中的所有复选框时,就会出现此状态。如果用户随后取消选中其中一个复选框,根复选框将不再表示“全部”选中,因此应处于不确定状态。
<progress>
元素还具有可设置样式的不确定状态。一种常见的用例是为其添加条纹外观,以表明还需要多少未知。
:placeholder-shown
如果某个表单字段具有 placeholder
属性,但没有值,则可以使用 :placeholder-shown
伪类为该状态附加样式。 只要该字段中有内容(无论是否包含 placeholder
),此状态就不再适用。
验证状态
您可以使用伪类(例如 :valid
、:invalid
和 :in-range
)来响应 HTML 表单验证。:valid
和 :invalid
伪类适用于需要匹配 pattern
才能成为有效字段的电子邮件字段等情形。此有效值状态可以向用户显示,帮助他们了解可以安全地移至下一个字段。
如果输入具有 min
和 max
(例如数值输入),且值在这些边界范围内,则可以使用 :in-range
伪类。
对于 HTML 表单,您可以使用 required
属性确定某个字段是否为必需字段。 :required
伪类将适用于必填字段。可以使用 :optional
伪类选择非必需字段。
按元素的索引、顺序和出现次数选择元素
有一组伪类可根据项在文档中的位置来选择项。
:first-child
和:last-child
如果您想查找第一个或最后一个商品,可以使用 :first-child
和 :last-child
。 这些伪类将返回同级元素组中的第一个或最后一个元素。
:only-child
您还可以使用 :only-child
伪类选择没有同级元素的元素。
:first-of-type
和:last-of-type
您可以选择 :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
您还可以指定第一个和最后一个子级以外的子级以及类型。 借助 :nth-child
和 :nth-of-type
伪类,您可以指定位于特定索引处的元素。CSS 选择器中的索引从 1 开始。
:nth-last-child()
和 :nth-last-of-type()
伪类从末尾开始计数,而不是从开头开始计数。
您还可以向这些伪类传递索引以外的其他内容。如果您想选择所有偶数元素,可以使用 :nth-child(even)
。
您还可以使用 An+B 微语法创建更复杂的选择器,以查找间隔规律的元素。
li:nth-child(3n+3) { background: yellow; }
此选择器选择从第 3 项开始的每第 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()
和 :nth-last-child()
还支持“of S”语法,可让您使用选择器过滤匹配项,类似于 :nth-of-type()
。li:nth-of-type(even)
等效于 :nth-child(even of li)
。虽然 :nth-of-type
仅允许您根据元素类型(例如 li
或 p
)进行过滤,但“of S”语法允许您根据任何选择器进行过滤。
如果您有表格,可能需要每隔一行添加条纹。虽然您可以使用 tr:nth-child(even)
来定位每隔一行,但如果您过滤掉某些行,此方法将无法正常运行。如果您通过应用 hidden
属性来实现过滤,则可以在选择器中添加 of :not([hidden])
,以便在选择偶数行之前预先过滤掉隐藏的项。
tr:nth-child(even of :not([hidden])){ background: lightgrey; }
您可以在此 nth-child 测试工具或此数量选择器工具上试用此类选择器。
:only-of-type
最后,您可以使用 :only-of-type
在一组同级元素中查找特定类型的唯一元素。如果您想选择仅包含一项的列表,或者想查找段落中唯一的粗体元素,此功能会非常有用。
查找空元素
有时,识别完全为空的元素会很有用,为此也提供了一个伪类。
:empty
如果某个元素没有子元素,则 :empty
伪类适用于该元素。 不过,子项不仅可以是 HTML 元素或文本节点,还可以是空白字符。当您调试以下 HTML 并想知道为什么它无法与 :empty
搭配使用时,这可能会让您感到困惑:
<div> </div>
原因是起始 <div>
和结束 <div>
之间存在一些空格,因此 :empty
将无法正常运行。
如果您对 HTML 的控制权有限,但又想隐藏空元素(例如所见即所得内容编辑器),: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()
如果您想查找 .post
元素中的所有 h2
、li
和 img
子元素,您可能会想到编写如下选择器列表:
.post h2, .post li, .post img { … }
借助 :is()
伪类,您可以编写更简洁的版本:
.post :is(h2, li, img) { /* ... */ }
:is
伪类不仅比选择器列表更简洁,而且更宽容。在大多数情况下,如果选择器列表中存在错误或不受支持的选择器,整个选择器列表将不再起作用。 如果 :is
伪类中传递的选择器存在错误,系统会忽略无效的选择器,但会使用有效的选择器。
:not()
您还可以使用 :not()
伪类排除商品。 例如,您可以使用它来设置所有不具有 class
属性的链接的样式。
a:not([class]) { color: blue; }
:not
伪类还有助于提高无障碍功能。 例如,<img>
必须具有 alt
,即使它是空值也是如此,因此您可以编写一条 CSS 规则,为无效图片添加粗红色轮廓:
img:not([alt]) { outline: 10px red; }
:has()
如果您想根据元素内包含的内容来设置元素的样式,该怎么办?您可以使用 :has()
伪类来实现此目的。例如,您可能希望为包含图标的按钮应用样式。
button:has(svg) { /* ... */ }
在最基本的配置中(如上例所示),您可以将 :has()
视为父选择器。您还可以将匹配父选择器与其他选择器结合使用,以定位其他元素。
form:has(input:valid) label { font-weight: bold; } form:has(input:valid) label::after { content: "✅"; }
在此示例中,当表单输入具有 valid
伪类时,我们会为标签元素和 label::after
伪元素应用样式。
:has()
伪类不能嵌套在另一个 :has()
中,但可以与其他伪类结合使用。
:is(h1, h2, h3):has(a) { /* ... */ }
选择器列表非常严格,如果列表中的任何选择器无效,系统都会忽略所有样式规则。
.my-element:has(img, ::before) { /* any styles here will be discarded since pseudo elements can't be included in the :has() selector list */ }
检验您的掌握情况
测试您对伪类的了解程度
伪类就像是动态应用于元素的类,而伪元素则作用于元素本身。
:
作为键区分字符以下哪些是功能性伪类?
:is()
:target
()
,表示它们接受参数。:empty
()
,表示它们接受参数。:not()
以下哪些伪类是因用户互动而产生的?
:hover
:press
:squeeze
:target
:focus-within
以下哪些是 <form>
状态伪类?
:enabled
:fresh
:indeterminate
:checked
:in-range
:loading
:valid