Skip to content

CSS 伪类:动态样式与用户交互的艺术

理解伪类

伪类(Pseudo-class)是 CSS 中的一种特殊选择器,它基于元素的状态位置来选择元素,而不是基于元素本身的属性。可以把伪类理解为"在特定条件下才会激活的样式开关"。

伪类使用单冒号 : 语法,例如 :hover:first-child:checked 等。它们让我们能够在不修改 HTML 结构、不使用 JavaScript 的情况下,实现丰富的交互效果和精确的样式控制。

css
/* 基本语法 */
selector:pseudo-class {
  property: value;
}

/* 实例 */
button:hover {
  background-color: #3498db;
}

用户行为伪类

这类伪类响应用户的操作,是创建交互体验的核心工具。

:hover - 鼠标悬停

当鼠标指针悬停在元素上时触发:

css
/* 基础悬停效果 */
a:hover {
  color: #e74c3c;
  text-decoration: underline;
}

/* 按钮悬停 */
.button:hover {
  background-color: #2980b9;
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  transition: all 0.3s ease;
}

/* 卡片悬停 */
.card:hover {
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

.card:hover img {
  transform: scale(1.05);
}

/* 导航菜单 */
.nav-item:hover .dropdown-menu {
  display: block;
  opacity: 1;
  visibility: visible;
}

:active - 激活状态

元素被点击时的瞬间状态:

css
button:active {
  transform: scale(0.98);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.link:active {
  color: #c0392b;
}

/* 涟漪效果的基础 */
.ripple:active::after {
  animation: ripple-animation 0.6s ease-out;
}

:focus - 焦点状态

元素获得焦点时(通常是表单元素或可聚焦的元素):

css
/* 输入框焦点 */
input:focus {
  outline: none;
  border-color: #3498db;
  box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}

textarea:focus {
  border-color: #3498db;
  background-color: #f8f9fa;
}

/* 可访问性增强 */
.button:focus {
  outline: 2px solid #3498db;
  outline-offset: 2px;
}

/* 焦点可见性控制 */
.nav-link:focus-visible {
  outline: 2px dashed #3498db;
  outline-offset: 4px;
}

:focus-within - 内部焦点

当元素本身或其任何后代元素获得焦点时触发:

css
/* 表单组焦点高亮 */
.form-group:focus-within {
  background-color: #f8f9fa;
  border-left: 3px solid #3498db;
  padding-left: 17px;
}

/* 搜索框容器 */
.search-container:focus-within {
  box-shadow: 0 4px 12px rgba(52, 152, 219, 0.2);
}

.search-container:focus-within .search-icon {
  color: #3498db;
}

/* 侧边栏高亮 */
.sidebar:focus-within {
  border-right: 2px solid #3498db;
}

结构伪类

结构伪类基于元素在 DOM 树中的位置关系来选择元素。

:first-child 和 :last-child

css
/* 第一个子元素 */
li:first-child {
  border-top: none;
}

.card:first-child {
  margin-top: 0;
}

/* 最后一个子元素 */
li:last-child {
  border-bottom: none;
}

.section:last-child {
  margin-bottom: 0;
}

/* 组合使用 */
.breadcrumb li:first-child::before {
  content: none; /* 移除第一项的分隔符 */
}

:nth-child() - 灵活的位置选择

nth-child() 是最强大的结构伪类之一,支持多种参数:

css
/* 选择偶数项 */
tr:nth-child(even) {
  background-color: #f8f9fa;
}

/* 选择奇数项 */
tr:nth-child(odd) {
  background-color: white;
}

/* 选择第3个 */
li:nth-child(3) {
  color: #e74c3c;
}

/* 选择前3个 */
li:nth-child(-n + 3) {
  font-weight: bold;
}

/* 从第4个开始 */
li:nth-child(n + 4) {
  opacity: 0.7;
}

/* 每3个一组,选择第一个 */
.item:nth-child(3n + 1) {
  clear: left;
}

/* 实用案例:网格布局 */
.gallery-item:nth-child(4n) {
  margin-right: 0; /* 每行最后一个不需要右边距 */
}

/* 高级:选择中间的项 */
li:nth-child(n + 3):nth-child(-n + 7) {
  color: #3498db; /* 选择第3到第7项 */
}

:nth-of-type()

:nth-child() 类似,但只计算同类型的元素:

css
/* 选择所有偶数段落 */
p:nth-of-type(even) {
  background-color: #f8f9fa;
}

/* 选择前2个 h2 标题 */
h2:nth-of-type(-n + 2) {
  color: #e74c3c;
  font-size: 2em;
}

/* 实际应用:文章样式 */
article p:nth-of-type(1) {
  font-size: 1.2em; /* 第一段引言效果 */
  font-style: italic;
}

:only-child 和 :only-of-type

css
/* 唯一子元素 */
.container p:only-child {
  margin: 0; /* 只有一个段落时不需要边距 */
}

/* 唯一的此类型元素 */
li:only-of-type {
  list-style: none; /* 列表只有一项时移除符号 */
}

/* 实用场景 */
.button-group button:only-child {
  border-radius: 4px; /* 只有一个按钮时四角都圆角 */
}

:empty - 空元素

选择没有任何子元素(包括文本节点)的元素:

css
/* 隐藏空的容器 */
.notification:empty {
  display: none;
}

/* 空状态提示 */
.list:empty::before {
  content: "暂无数据";
  color: #999;
  font-style: italic;
}

/* 空表格单元格 */
td:empty {
  background-color: #f5f5f5;
}

td:empty::after {
  content: "-";
  color: #ccc;
}

表单伪类

这些伪类专门用于处理表单元素的各种状态。

:disabled 和 :enabled

css
/* 禁用状态 */
input:disabled,
button:disabled {
  background-color: #e9ecef;
  color: #6c757d;
  cursor: not-allowed;
  opacity: 0.6;
}

/* 启用状态 */
input:enabled {
  background-color: white;
  cursor: text;
}

/* 禁用的按钮不响应悬停 */
button:disabled:hover {
  background-color: #e9ecef;
  transform: none;
}

:checked - 选中状态

用于单选框、复选框和 <option> 元素:

css
/* 自定义复选框 */
input[type="checkbox"]:checked + label::before {
  background-color: #3498db;
  border-color: #3498db;
}

input[type="checkbox"]:checked + label::after {
  content: "✓";
  color: white;
  position: absolute;
  left: 4px;
  top: 0;
}

/* 切换开关效果 */
.switch input:checked + .slider {
  background-color: #3498db;
}

.switch input:checked + .slider::before {
  transform: translateX(20px);
}

/* 标签页 */
.tab-input:checked + .tab-label {
  background-color: white;
  border-bottom-color: white;
  color: #3498db;
}

.tab-input:checked ~ .tab-content {
  display: block;
}

:required 和 :optional

css
/* 必填字段标识 */
input:required {
  border-left: 3px solid #e74c3c;
}

input:required + label::after {
  content: " *";
  color: #e74c3c;
}

/* 可选字段 */
input:optional {
  border-left: 3px solid #95a5a6;
}

:valid 和 :invalid

基于 HTML5 表单验证规则:

css
/* 有效输入 */
input:valid {
  border-color: #27ae60;
}

input:valid + .icon::before {
  content: "✓";
  color: #27ae60;
}

/* 无效输入 */
input:invalid {
  border-color: #e74c3c;
}

input:invalid + .error-message {
  display: block;
  color: #e74c3c;
  font-size: 0.875em;
  margin-top: 4px;
}

/* 避免初始状态显示错误 */
input:invalid:not(:focus):not(:placeholder-shown) {
  border-color: #e74c3c;
}

:in-range 和 :out-of-range

用于带有 minmax 属性的输入框:

css
input[type="number"]:in-range {
  border-color: #27ae60;
  background-color: #d5f4e6;
}

input[type="number"]:out-of-range {
  border-color: #e74c3c;
  background-color: #fadbd8;
}

:placeholder-shown

当输入框显示占位符文本时:

css
input:placeholder-shown {
  border-color: #ddd;
}

/* 浮动标签效果 */
input:not(:placeholder-shown) + label {
  transform: translateY(-24px) scale(0.85);
  color: #3498db;
}

链接伪类

专门用于 <a> 元素的伪类:

css
/* 未访问的链接 */
a:link {
  color: #3498db;
}

/* 已访问的链接 */
a:visited {
  color: #9b59b6;
}

/* 链接伪类顺序很重要:LVHA */
/* :link - :visited - :hover - :active */

/* 实际应用 */
.nav-link:link,
.nav-link:visited {
  color: #2c3e50;
  text-decoration: none;
}

.nav-link:hover {
  color: #3498db;
}

.nav-link:active {
  color: #2980b9;
}

否定伪类

:not() 选择器允许你排除特定元素:

css
/* 除了最后一个,所有 li 都有下边框 */
li:not(:last-child) {
  border-bottom: 1px solid #ddd;
}

/* 除了禁用的,所有按钮都可悬停 */
button:not(:disabled):hover {
  background-color: #2980b9;
}

/* 排除特定类 */
input:not(.no-border) {
  border: 1px solid #ddd;
}

/* 复杂组合 */
a:not([href^="http"]):not([href^="mailto"]) {
  /* 只选择内部链接 */
  color: #2c3e50;
}

/* 多个条件 */
input:not(:disabled):not(:read-only):focus {
  background-color: #f8f9fa;
}

其他实用伪类

:target - URL 片段目标

当 URL 的片段标识符匹配元素的 ID 时:

css
/* 高亮锚点目标 */
:target {
  background-color: #fff3cd;
  border-left: 4px solid #ffc107;
  padding-left: 16px;
  animation: highlight 2s ease;
}

@keyframes highlight {
  from {
    background-color: #fff3cd;
  }
  to {
    background-color: transparent;
  }
}

/* 模态框 */
.modal:target {
  display: block;
  opacity: 1;
  visibility: visible;
}

:root - 根元素

选择文档的根元素,通常用于定义 CSS 变量:

css
:root {
  --primary-color: #3498db;
  --secondary-color: #2ecc71;
  --font-size-base: 16px;
  --spacing-unit: 8px;
}

.button {
  background-color: var(--primary-color);
  padding: calc(var(--spacing-unit) * 2);
}

实战案例

智能表单验证

css
.form-field {
  position: relative;
  margin-bottom: 20px;
}

/* 初始状态 */
.form-field input {
  border: 2px solid #ddd;
  padding: 12px;
  transition: all 0.3s;
}

/* 焦点状态 */
.form-field input:focus {
  border-color: #3498db;
  outline: none;
}

/* 有效输入 */
.form-field input:valid:not(:placeholder-shown) {
  border-color: #27ae60;
  padding-right: 40px;
}

.form-field input:valid:not(:placeholder-shown) + .status-icon::after {
  content: "✓";
  color: #27ae60;
}

/* 无效输入 */
.form-field input:invalid:not(:focus):not(:placeholder-shown) {
  border-color: #e74c3c;
}

.form-field input:invalid:not(:focus):not(:placeholder-shown) ~ .error {
  display: block;
}

/* 必填字段标识 */
.form-field input:required ~ label::after {
  content: " *";
  color: #e74c3c;
}

响应式卡片网

css
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

/* 每行第一个卡片 */
.card:nth-child(4n + 1) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

/* 悬停效果 */
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}

/* 除了悬停的,其他卡片降低透明度 */
.card-grid:hover .card:not(:hover) {
  opacity: 0.7;
}

纯 CSS 手风琴

css
.accordion-item input[type="checkbox"] {
  display: none;
}

.accordion-header {
  cursor: pointer;
  padding: 15px;
  background-color: #f8f9fa;
  border-bottom: 1px solid #ddd;
}

.accordion-content {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

input[type="checkbox"]:checked ~ .accordion-content {
  max-height: 500px;
}

input[type="checkbox"]:checked ~ .accordion-header {
  background-color: #3498db;
  color: white;
}

input[type="checkbox"]:checked ~ .accordion-header::after {
  transform: rotate(180deg);
}

总结

伪类是 CSS 中最强大的工具之一。掌握伪类,你就能在不依赖 JavaScript 的情况下创建丰富的交互效果,让用户界面更加动态和友好。

核心要点

  • 用户行为伪类:响应用户操作,创建交互体验
    • :hover - 鼠标悬停状态
    • :active - 激活状态
    • :focus - 焦点状态
    • :focus-within - 内部焦点状态
  • 结构伪类:基于元素在 DOM 树中的位置选择
    • :first-child, :last-child - 首尾子元素
    • :nth-child(), :nth-of-type() - 灵活的位置选择
    • :only-child, :empty - 特殊状态元素
  • 表单伪类:专门处理表单元素的各种状态
    • :disabled, :enabled - 禁用/启用状态
    • :checked - 选中状态
    • :valid, :invalid - 验证状态
    • :placeholder-shown - 占位符显示状态
  • 否定伪类:not() 排除特定元素
  • 实战应用:智能表单验证、响应式卡片、纯 CSS 交互组件