CSS 伪类与伪元素

伪类和伪元素是特殊的选择器,它们不选择 HTML 中实际存在的元素,而是选择元素的特定状态或文档中的虚拟部分

伪类(Pseudo-classes)

伪类用单冒号 : 开头,表示元素的状态。它们随着用户交互或文档结构变化而动态生效。

用户交互伪类

最常用的一类伪类,响应鼠标、键盘等用户操作:

css
/* 鼠标悬停 */
a:hover {
  color: #2563eb;
  text-decoration: underline;
}

/* 获得焦点(Tab 导航或点击) */
input:focus {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

/* 鼠标按下时 */
button:active {
  transform: scale(0.97);
}

链接状态建议按 LVHA 顺序书写——:link:visited:hover:active:focus 不属于 LVHA 序列,可与 :hover 并列写在任意位置。常见组合是 :hover, :focus { ... }

链接状态伪类

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

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

表单状态伪类

css
/* 选中的复选框/单选框 */
input:checked + label {
  color: #2563eb;
  font-weight: 500;
}

/* 禁用的表单控件 */
input:disabled {
  background: #f1f5f9;
  color: #94a3b8;
  cursor: not-allowed;
}

/* 输入无效内容时 */
input:invalid {
  border-color: #ef4444;
}

/* 可选(非必填)的输入框 */
input:optional {
  border-style: dashed;
}

/* 必填字段 */
input:required {
  border-left: 3px solid #2563eb;
}
html
<form>
  <label><input type="checkbox" checked> <span>已选中的复选框</span></label><br>
  <label><input type="checkbox"> <span>未选中的复选框</span></label><br>
  <input type="text" disabled value="禁用状态"><br>
  <input type="text" required placeholder="必填字段"><br>
  <input type="email" placeholder="输入邮箱(:optional)">
</form>

结构伪类

根据元素在文档树中的位置选择:

伪类选中条件
:first-child父元素的第一个子元素
:last-child父元素的最后一个子元素
:nth-child(n)父元素的第 n 个子元素
:nth-child(odd)奇数位子元素
:nth-child(even)偶数位子元素
:only-child父元素的唯一子元素
:first-of-type同类型中的第一个
:last-of-type同类型中的最后一个
:nth-of-type(n)同类型中的第 n 个
css
/* 列表的偶数行加背景色(斑马条纹) */
tr:nth-child(even) {
  background: #f8fafc;
}

/* 第一个段落加粗 */
p:first-child {
  font-weight: 500;
}

/* 只有一张图片时占满宽度 */
img:only-child {
  width: 100%;
}

/* 末尾元素去掉下边距 */
li:last-child {
  margin-bottom: 0;
}

:nth-child(n) 详解

n 从 0 开始计数,可以用公式表达:

css
/* 第 3 个 */
:nth-child(3)

/* 所有奇数:1, 3, 5, ... */
:nth-child(odd)

/* 所有偶数:2, 4, 6, ... */
:nth-child(even)

/* 每 3 个选 1 个:3, 6, 9, ... */
:nth-child(3n)

/* 从第 2 个开始每 3 个:2, 5, 8, ... */
:nth-child(3n+2)

/* 前 3 个:1, 2, 3 */
:nth-child(-n+3)

伪元素(Pseudo-elements)

伪元素用双冒号 :: 开头,创建文档中不存在的虚拟元素

早期 CSS 中伪元素也用单冒号(如 :before),现代浏览器对两者都兼容。推荐使用双冒号以与伪类区分。

::before::after

最常用的两个伪元素,在元素内容之前/之后插入虚拟内容。必须配合 content 属性使用

css
/* 在引用文字前后加引号 */
blockquote::before {
  content: "「";
}
blockquote::after {
  content: "」";
}

/* 给外部链接加图标 */
a[href^="https"]::after {
  content: " ↗";
  font-size: 0.8em;
  opacity: 0.5;
}

/* 装饰性分割线 */
.section-divider::before {
  content: "";
  display: block;
  width: 60px;
  height: 3px;
  background: #2563eb;
  margin-bottom: 2rem;
}

content 可以是文字、空字符串(用于纯装饰)、或 attr() 读取属性值:

css
/* 在链接后显示 URL */
a[href^="http"]::after {
  content: " (" attr(href) ")";
  font-size: 0.8em;
  color: #94a3b8;
}
html
<p>访问 <a href="https://coodocs.com">Coodocs</a> 了解更多。</p>

其他伪元素

伪元素选中部分
::first-line文本的第一行
::first-letter文本的第一个字母
::selection用户选中的文本
::placeholderinput/textarea 的占位文字
::marker列表项的标记符号(圆点、数字等)
css
/* 首字下沉 */
p.intro::first-letter {
  font-size: 3rem;
  font-weight: 700;
  float: left;
  margin-right: 0.25rem;
  line-height: 1;
}

/* 选中文本的颜色 */
::selection {
  background: #2563eb;
  color: white;
}

/* 输入框占位文字样式 */
input::placeholder {
  color: #94a3b8;
  font-style: italic;
}

/* 列表标记颜色 */
li::marker {
  color: #2563eb;
}

一个元素只能有一个 ::before 和一个 ::after。它们的 display 默认为 inline,需要设置 display: blockdisplay: inline-block 才能使用宽高。