Menu

CSS 伪类:nth-child、not、first-child 与 focus

伪类按位置或状态选择元素::nth-child()、:first-child、:not()、:focus、:checked、:has() 等。本文讲解伪类的语法、an+b 公式(附在线测试器),以及 nth-child 与 nth-of-type 的区别。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

伪类是什么

伪类是冒号后面的一个关键字,它按元素在文档中的位置或元素的状态来选择元素。你把它附加在普通选择器后面:li:first-child、input:focus、a:hover。

链接和鼠标相关的状态伪类(:hover、:active、:visited)有专门的页面:CSS hover。

:nth-child() 与 an+b 公式

:nth-child() 接受一个数字、一个关键字或一个 an+b 公式。浏览器会依次代入 n = 0、1、2……,匹配公式得出的每一个位置(位置从 1 开始)。

公式匹配的位置含义
33第三个子元素
odd 或 2n+11, 3, 5, ...奇数行
even 或 2n2, 4, 6, ...偶数行
3n3, 6, 9, ...每隔三个
n+44, 5, 6, ...第四个及之后
-n+31, 2, 3前三个
3n+11, 4, 7, ...从第一个开始,每隔三个

输入一个公式,看看哪些项被匹配:

试试 odd、even、4、n+7、-n+5 和 2n+3。无效的公式什么都不匹配。

从末尾开始计数的版本是 :nth-last-child():li:nth-last-child(-n+2) 选择最后两项。

nth-child 与 nth-of-type 的区别

:nth-child() 统计所有兄弟元素,不管它们是什么标签,然后才检查选择器的其余部分。:nth-of-type() 只统计相同标签的兄弟元素。一旦兄弟元素混在一起,区别就显现出来了:

两端也有同样成对的伪类::first-child / :first-of-type、:last-child / :last-of-type、:only-child / :only-of-type。

:not()、:is() 与 :where()

伪类示例匹配
:not(X)li:not(.done)不匹配 X 的元素
:is(X, Y):is(h1, h2, h3) a匹配列表中任意一项的元素
:where(X, Y):where(ul, ol) li和 :is() 相同,但优先级为零
:has(X)li:has(> input:checked)内部包含 X 匹配项的元素

:not() 是日常最常用的一个,例如在各项之间加分隔线,但最后一项后面不加:

状态伪类:focus、checked、disabled、invalid

伪类匹配
:focus获得键盘或鼠标焦点的元素
:focus-visible获得焦点,并且浏览器判断应该显示焦点环(通常是键盘焦点)
:focus-within内部包含获得焦点元素的元素
:checked被勾选的复选框、单选按钮或被选中的 <option>
:disabled / :enabled被禁用(或未被禁用)的表单控件
:required / :optional带有或不带 required 的输入框
:invalid / :valid值未通过或通过验证的输入框
:user-invalid无效,但只在用户与它交互之后才匹配
:placeholder-shown当前正在显示占位文字的输入框
:empty没有任何子元素的元素,连文字都没有
:targetid 与 URL 中 #fragment 相同的元素

点击邮箱输入框:通过 :focus-within,它的标签会变成蓝色。输入一个不是邮箱的内容,然后离开输入框::user-invalid 会让边框变成琥珀色。如果用普通的 :invalid,这个必填的空输入框在你碰它之前就已经被标成琥珀色了。

无论你怎样处理 :focus,都要保留可见的焦点样式。去掉轮廓线却不提供替代样式,使用键盘的用户就看不出自己当前在哪里。

:has(),父元素选择器

:has() 根据元素包含的内容来匹配它。它就是大家期待已久的“父元素选择器”,在当前的 Chrome、Firefox 和 Safari 中都能使用。

选择另一个套餐:整张卡片会跟随单选按钮变化,完全不需要 JavaScript。

常见错误

  • 冒号前面多了空格。 li :first-child 的意思是“li 内部的第一个子元素”。应写成 li:first-child。
  • 以为 p:nth-child(1) 表示“第一个 p”。 它的意思是“第一个子元素,如果它是 p 的话”。要选第一个 p,请用 :first-of-type。
  • 从 0 开始计数。 位置从 1 开始::nth-child(0) 什么都匹配不到。
  • 去掉焦点轮廓线。 写 :focus { outline: none } 却不提供替代样式,会破坏键盘导航。
  • 混淆 : 和 ::。 :before 是伪元素 ::before 的旧写法;伪类始终只用一个冒号。

常见问题

CSS 中的伪类是什么?

伪类是冒号后面的一个关键字,它按状态或位置而不是按名称来选择元素,例如 a:hover、li:first-child 或 input:focus。它附加在普通选择器后面,大多数伪类在优先级上和类一样计算(:where() 计为零)。

CSS 中的 nth-child 是怎么工作的?

:nth-child(an+b) 匹配在兄弟元素中位置为 a×n+b 的元素,n 依次取 0、1、2 等,位置从 1 开始计数。:nth-child(3) 是第三个子元素,:nth-child(odd) 或 2n+1 是每个奇数位置的元素,:nth-child(n+4) 是第四个及之后的元素。

nth-child 和 nth-of-type 有什么区别?

:nth-child() 先统计所有兄弟元素,再检查选择器的其余部分;:nth-of-type() 只统计同一类型元素的兄弟元素。在一个 h2 后面跟着若干段落的列表中,p:nth-child(1) 什么都匹配不到,而 p:nth-of-type(1) 匹配第一个段落。

CSS 中的 :not() 怎么用?

把要排除的选择器写在括号里:li:not(.done) 匹配所有没有 done 类的列表项。它也接受一个列表,例如 input:not([type="checkbox"], [type="radio"])。

伪类和伪元素有什么区别?

伪类(一个冒号,:hover)选择处于某种状态的一个完整的现有元素。伪元素(两个冒号,::before)针对的是元素的某个部分,或者用来创建生成的内容。

Coddy 编程语言插图

和 Coddy 一起学编程

开始