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
用于带有 min 和 max 属性的输入框:
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 交互组件