CSS 零基础教程

CSS 伪类选择器

CSS 伪类是一种用于选择元素特定状态或位置的关键字,它们可以为现有元素添加特殊效果,而无需在 HTML 中添加新的类或 ID。

通过伪类,开发者能够基于用户交互(如鼠标悬停)、元素在文档树中的位置(如第一个子元素)、或特定属性(如已访问链接)等条件来应用样式,极大地增强了 CSS 的选择能力和灵活性。

1. 什么是伪类?

伪类以冒号 : 开头,并附加到选择器后面,用于指定元素的特殊状态或位置。它们允许你根据元素在某个时刻或某个上下文中的情况来应用样式,而不是仅仅基于其在文档结构中的标签名、类或ID。理解伪类对于创建交互式和动态的网页至关重要。

1.1 伪类的作用

  • 响应用户交互: 例如,当用户将鼠标悬停在链接上时改变其颜色。
  • 基于元素状态: 根据表单输入字段是启用、禁用还是被选中来改变其样式。
  • 基于元素位置: 选择一个列表中第一个或最后一个项目,或者选择特定类型的Nth个子元素。
  • 基于文档结构: 应用样式到链接的已访问或未访问状态。

2. 常用伪类分类与示例

CSS 伪类可以根据其功能大致分为几类,每类都服务于不同的样式需求。

2.1 动态伪类 (User Action Pseudo-classes)

这些伪类响应用户与元素的交互。

  • :link
    • 描述: 选择所有未被访问的 <a> 元素。
a:link {
    color: blue;
}
  • :visited
    • 描述: 选择所有已被访问的 <a> 元素。出于隐私考虑,可样式化的属性受到严格限制(通常只能改变 color)。
a:visited {
    color: purple;
}
  • :hover
    • 描述: 选择鼠标指针悬停在其上的元素。
button:hover {
    background-color: lightgray;
}
  • :active
    • 描述: 选择被用户激活(例如,点击鼠标时)的元素。
button:active {
    background-color: darkgray;
    transform: translateY(1px);
}
  • :focus
    • 描述: 选择当前获得焦点的元素(通常是表单元素或链接)。
input:focus {
    border: 2px solid blue;
    outline: none; /* 移除浏览器默认的焦点轮廓 */
}
注意: 动态伪类的顺序很重要,通常遵循 LVHA 顺序(Link, Visited, Hover, Active)以确保所有状态都能正确应用。

2.2 UI 元素状态伪类 (UI Element States Pseudo-classes)

这些伪类选择处于特定 UI 状态的元素,常用于表单元素。

  • :enabled
    • 描述: 选择所有已启用的表单元素。
input:enabled {
    background-color: white;
}
  • :disabled
    • 描述: 选择所有被禁用的表单元素。
input:disabled {
    background-color: #eee;
    cursor: not-allowed;
}
  • :checked
    • 描述: 选择所有被选中的 radiocheckboxoption 元素。
input[type="checkbox"]:checked + label {
    font-weight: bold;
}
  • :read-only
    • 描述: 选择设置了 readonly 属性的输入字段。
input:read-only {
    background-color: #f0f0f0;
    border-color: #ccc;
}
  • :read-write
    • 描述: 选择用户可编辑的输入字段。
input:read-write {
    border: 1px solid blue;
}
  • :valid
    • 描述: 选择内容通过验证的 inputform 元素。
input:valid {
    border-color: green;
}
  • :invalid
    • 描述: 选择内容未通过验证的 inputform 元素。
input:invalid {
    border-color: red;
}

2.3 结构性伪类 (Structural Pseudo-classes)

这些伪类根据元素在文档树中的位置来选择元素。

  • :first-child
    • 描述: 选择父元素的第一个子元素。
ul li:first-child {
    font-weight: bold;
}
  • :last-child
    • 描述: 选择父元素的最后一个子元素。
ul li:last-child {
    border-bottom: none;
}
  • :nth-child(n)
    • 描述: 选择父元素的第 n 个子元素。n 可以是数字、关键字(even, odd)或公式(An+B)。
tr:nth-child(even) { /* 选择偶数行 */
    background-color: #f2f2f2;
}
p:nth-child(3n+1) { /* 选择第1, 4, 7...个p元素 */
    color: green;
}
  • :nth-last-child(n)
    • 描述: 从父元素的最后一个子元素开始倒数,选择第 n 个子元素。
li:nth-last-child(2) { /* 选择倒数第二个li */
    text-decoration: underline;
}
  • :first-of-type
    • 描述: 选择其父元素的指定类型的第一个子元素。
div p:first-of-type { /* 选择div内的第一个p元素 */
    color: red;
}
  • :last-of-type
    • 描述:选择其父元素的指定类型的最后一个子元素。
div p:last-of-type {
    color: blue;
}
  • :nth-of-type(n)
    • 描述: 选择其父元素的指定类型的第 n 个子元素。
span:nth-of-type(2) { /* 选择父元素中第二个span */
    font-style: italic;
}
  • :nth-last-of-type(n)
    • 描述: 从其父元素的指定类型的最后一个子元素开始倒数,选择第 n 个子元素。
img:nth-last-of-type(1) { /* 选择父元素中最后一个图片 */
    border: 2px solid orange;
}
  • :only-child
    • 描述: 选择是其父元素的唯一子元素的元素。
p:only-child {
    background-color: yellow;
}
  • :only-of-type
    • 描述: 选择是其父元素的指定类型的唯一子元素的元素。
div:only-of-type {
    border: 1px dashed gray;
}
  • :empty
    • 描述: 选择不包含任何子元素(包括文本节点)的元素。
div:empty {
    height: 20px;
    background-color: lightgray;
}
  • :root
    • 描述: 选择文档的根元素(通常是 <html> )。
:root {
    --main-color: #336699; /* 定义CSS变量 */
}
  • :not(selector)
    • 描述: 选择不匹配括号内选择器的元素(否定伪类)。
li:not(.special) {
    color: #333;
}
  • :has(selector) (CSS Selectors Level 4)
    • 描述: 选择包含(或“拥有”)一个或多个选择器所匹配的元素的元素。
div:has(p) { /* 选择包含p元素的div */
    border: 1px solid green;
}
  • :where(selector-list) (CSS Selectors Level 4)
    • 描述: 接受一个选择器列表作为参数,并选择其中任意一个选择器匹配的元素,且优先级为 0。
:where(h1, h2, h3) {
    margin-top: 0;
}
  • :is(selector-list) (CSS Selectors Level 4)
    • 描述: 接受一个选择器列表作为参数,并选择其中任意一个选择器匹配的元素。其优先级由列表中最高优先级的选择器决定。
:is(h1, h2):hover {
    color: blue;
}

2.4 语言伪类 (Linguistic Pseudo-classes)

  • :lang(language)
    • 描述: 选择 lang 属性设置为指定语言的元素。
p:lang(zh) {
    font-family: 'Microsoft YaHei', sans-serif;
}
p:lang(en) {
    font-family: Arial, sans-serif;
}

2.5 时间轴伪类 (Time-dimensional Pseudo-classes)

这些伪类用于选择处于特定播放状态的媒体元素,如视频或音频。

  • :playing
    • 描述: 选择当前正在播放的媒体元素。
video:playing {
    border: 2px solid green;
}
  • :paused
    • 描述: 选择当前已暂停的媒体元素。
video:paused {
    border: 2px solid red;
}

3. 最佳实践与注意事项

  • LVHA 顺序: 对于链接伪类(:link, :visited, :hover, :active),始终遵循这个顺序来编写 CSS 规则,以确保所有状态都能正确应用。:active 应该放在 :hover 之后,因为它代表一个更具体的、短暂的状态。
  • 可访问性: 结合 :focus 伪类提供清晰的焦点指示,这对于键盘用户至关重要。移除浏览器默认 outline 后,务必提供自定义的视觉焦点样式。
  • 性能考量: 复杂的结构性伪类(如 nth-child 配合复杂公式)在大型文档中可能会稍微影响性能,但对于大多数现代应用来说,这不是一个主要问题。
  • 浏览器兼容性: 大多数伪类都有良好的浏览器支持。然而,一些较新的伪类(如 :has, :where, :is)可能在旧版本浏览器中不受支持,使用时需注意兼容性,或使用 Polyfill。
  • 级联和特异性: 伪类的特异性(specificity)与普通类选择器相同。理解 CSS 级联规则对于解决样式冲突至关重要。
  • :not() 的局限性: :not() 只能否定简单的选择器,不能否定复杂选择器列表,并且不能否定另一个 not()。它也不会增加选择器的特异性。
  • :checked 与自定义表单: :checked 伪类在自定义 radiocheckbox 样式时非常有用,通常结合 + (相邻兄弟选择器) 来改变相关联 label 的样式。

通过熟练运用这些 CSS 伪类,开发者能够创建出更加动态、交互丰富且易于维护的网页界面。它们是 CSS 强大选择能力的核心组成部分,使得样式可以根据元素的各种条件和状态进行细粒度控制。