CSS3 结构伪类选择器

CSS3 的结构伪类选择器是基于文档结构来选择元素的一组强大选择器。它们允许我们根据元素在文档中的位置、类型等结构信息来精确选择元素,而不需要添加额外的类名或 ID。

结构伪类选择器概述

结构伪类选择器能够根据元素在文档树中的位置关系来选择元素,这些选择器特别适合用于创建样式模式,如斑马纹表格、列表样式等。使用结构伪类选择器可以减少 HTML 中的类名使用,保持代码的简洁性。

基础结构伪类

:first-child

选择作为父元素的第一个子元素的元素。

/* 选择每个列表的第一个项目 */
li:first-child {
  font-weight: bold;
  color: #007bff;
}

/* 选择每个段落的第一个字母(配合伪元素) */
p:first-child::first-letter {
  font-size: 2em;
  color: #dc3545;
}

实际应用:

/* 导航菜单 */
.nav li:first-child {
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
}

/* 表格第一行 */
table tr:first-child {
  background: #f8f9fa;
  font-weight: bold;
}

/* 卡片组第一个卡片 */
.card-group .card:first-child {
  border-top-left-radius: 8px;
  border-bottom-left-radius: 8px;
}

:last-child

选择作为父元素的最后一个子元素的元素。

/* 选择每个列表的最后一个项目 */
li:last-child {
  margin-bottom: 0;
  border-bottom: none;
}

/* 选择导航的最后一个链接 */
.nav li:last-child a {
  border-right: none;
}

实际应用:

/* 列表样式 */
ul li {
  border-bottom: 1px solid #eee;
  padding: 10px 0;
}

ul li:last-child {
  border-bottom: none;
}

/* 导航菜单 */
.nav li {
  border-right: 1px solid #ddd;
}

.nav li:last-child {
  border-right: none;
}

:only-child

选择作为父元素的唯一子元素的元素。

/* 选择只有单个子元素的容器 */
.container > div:only-child {
  width: 100%;
}

/* 选择单个列表项 */
ul li:only-child {
  list-style-type: none;
  padding-left: 0;
}

实际应用:

/* 单个按钮居中 */
.button-container button:only-child {
  display: block;
  margin: 0 auto;
}

/* 单个图片全宽 */
.image-container img:only-child {
  width: 100%;
  height: auto;
}

:empty

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

/* 选择空元素 */
div:empty {
  display: none;
}

/* 选择空的段落 */
p:empty {
  min-height: 1em;
  background: #f8f9fa;
  border: 1px dashed #ccc;
}

/* 选择空的列表项 */
li:empty {
  display: none;
}

实际应用:

/* 隐藏空元素 */
.sidebar .widget:empty {
  display: none;
}

/* 空状态提示 */
.empty-state {
  padding: 40px;
  text-align: center;
  color: #6c757d;
}

.empty-state:empty::before {
  content: "暂无数据";
  display: block;
}

高级结构伪类

:nth-child(n)

选择父元素的第 n 个子元素。n 可以是数字、关键词或公式。

/* 选择第 3 个子元素 */
li:nth-child(3) {
  color: red;
}

/* 选择奇数子元素 */
li:nth-child(odd) {
  background: #f5f5f5;
}

/* 选择偶数子元素 */
li:nth-child(even) {
  background: #fff;
}

/* 使用公式选择 */
li:nth-child(3n) {
  font-weight: bold;
}

li:nth-child(2n+1) {
  background: #f0f0f0;
}

实际应用:

/* 斑马纹表格 */
table tr:nth-child(even) {
  background: #f8f9fa;
}

table tr:nth-child(odd) {
  background: white;
}

/* 网格布局 */
.grid-item:nth-child(3n+1) {
  clear: left;
}

/* 列表样式 */
ul li:nth-child(5n) {
  margin-bottom: 20px;
}

:nth-last-child(n)

选择父元素的倒数第 n 个子元素。

/* 选择倒数第 2 个子元素 */
li:nth-last-child(2) {
  color: blue;
}

/* 选择倒数奇数子元素 */
li:nth-last-child(odd) {
  font-style: italic;
}

/* 选择最后 3 个子元素 */
li:nth-last-child(-n+3) {
  color: green;
}

实际应用:

/* 最后几个元素特殊样式 */
.news-list li:nth-last-child(-n+3) {
  background: #e3f2fd;
}

/* 倒数第 1 个和第 2 个 */
ul li:nth-last-child(1),
ul li:nth-last-child(2) {
  font-weight: bold;
}

:nth-of-type(n)

选择父元素中同类型元素的第 n 个元素。

/* 选择第 2 个段落 */
p:nth-of-type(2) {
  text-indent: 2em;
}

/* 选择奇数图片 */
img:nth-of-type(odd) {
  float: left;
  margin: 0 10px 10px 0;
}

/* 选择偶数图片 */
img:nth-of-type(even) {
  float: right;
  margin: 0 0 10px 10px;
}

实际应用:

/* 文章排版 */
article p:nth-of-type(1) {
  font-size: 1.2em;
  font-weight: bold;
}

article p:nth-of-type(2)::first-letter {
  font-size: 3em;
  float: left;
  line-height: 1;
}

/* 图片交替布局 */
.gallery img:nth-of-type(odd) {
  float: left;
  width: 48%;
  margin-right: 2%;
}

.gallery img:nth-of-type(even) {
  float: right;
  width: 48%;
  margin-left: 2%;
}

:nth-last-of-type(n)

选择父元素中同类型元素的倒数第 n 个元素。

/* 选择倒数第 1 个段落 */
p:nth-last-of-type(1) {
  font-weight: bold;
}

/* 选择最后 2 个图片 */
img:nth-last-of-type(-n+2) {
  border: 2px solid #007bff;
}

实际应用:

/* 最后一个段落特殊样式 */
article p:nth-last-of-type(1) {
  text-align: center;
  font-style: italic;
  color: #6c757d;
}

/* 最后几个图片标注 */
figure:nth-last-of-type(-n+3) img {
  border: 2px solid #007bff;
}

:first-of-type

选择父元素中同类型元素的第一个元素。

/* 选择第一个段落 */
p:first-of-type {
  font-size: 1.2em;
  font-weight: bold;
}

/* 选择第一个图片 */
img:first-of-type {
  width: 100%;
  height: auto;
}

实际应用:

/* 第一个段落首字母下沉 */
article p:first-of-type::first-letter {
  font-size: 3em;
  float: left;
  line-height: 1;
  margin-right: 0.1em;
}

/* 第一个图片全宽 */
.content img:first-of-type {
  width: 100%;
  height: auto;
  margin-bottom: 20px;
}

:last-of-type

选择父元素中同类型元素的最后一个元素。

/* 选择最后一个段落 */
p:last-of-type {
  text-align: center;
}

/* 选择最后一个列表 */
ul:last-of-type {
  margin-bottom: 0;
}

实际应用:

/* 最后一个段落底部间距 */
article p:last-of-type {
  margin-bottom: 0;
}

/* 最后一个标题样式 */
article h2:last-of-type {
  border-bottom: 2px solid #007bff;
  padding-bottom: 10px;
}

:only-of-type

选择父元素中唯一的某种类型元素。

/* 选择唯一的段落 */
p:only-of-type {
  text-align: center;
  font-size: 1.5em;
}

/* 选择唯一的图片 */
img:only-of-type {
  width: 100%;
  height: auto;
}

实际应用:

/* 单个图片居中 */
.image-wrapper img:only-of-type {
  display: block;
  margin: 0 auto;
}

/* 单个段落特殊样式 */
.content p:only-of-type {
  text-align: center;
  font-size: 1.2em;
  line-height: 1.8;
}

:root 伪类

:root 选择器选择文档的根元素,在 HTML 中就是 <html> 元素。它常用于定义全局 CSS 变量。

/* 定义全局变量 */
:root {
  --primary-color: #007bff;
  --secondary-color: #6c757d;
  --success-color: #28a745;
  --danger-color: #dc3545;
  --warning-color: #ffc107;
  --font-family: "Microsoft YaHei", sans-serif;
  --font-size: 16px;
  --line-height: 1.6;
}

/* 使用变量 */
body {
  font-family: var(--font-family);
  font-size: var(--font-size);
  line-height: var(--line-height);
}

.button {
  background: var(--primary-color);
  color: white;
}

实际应用:

/* 主题变量 */
:root {
  --bg-color: #ffffff;
  --text-color: #333333;
  --accent-color: #007bff;
}

/* 暗色主题 */
[data-theme="dark"] {
  --bg-color: #1a1a1a;
  --text-color: #ffffff;
  --accent-color: #4dabf7;
}

/* 使用主题变量 */
body {
  background: var(--bg-color);
  color: var(--text-color);
}

.button {
  background: var(--accent-color);
}

实际应用案例

1. 斑马纹表格

table {
  width: 100%;
  border-collapse: collapse;
}

table th,
table td {
  padding: 12px 15px;
  text-align: left;
  border-bottom: 1px solid #dee2e6;
}

table tr:nth-child(even) {
  background: #f8f9fa;
}

table tr:hover {
  background: #e9ecef;
}

table tr:first-child {
  background: #007bff;
  color: white;
}

table tr:last-child td {
  border-bottom: none;
}

2. 卡片网格

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

.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  overflow: hidden;
}

.card:nth-child(3n+1) {
  border-top: 4px solid #007bff;
}

.card:nth-child(3n+2) {
  border-top: 4px solid #28a745;
}

.card:nth-child(3n) {
  border-top: 4px solid #ffc107;
}

3. 文章排版

article {
  max-width: 800px;
  margin: 0 auto;
  line-height: 1.8;
}

article h2 {
  font-size: 2em;
  margin-top: 2em;
  margin-bottom: 1em;
}

article p {
  margin-bottom: 1.5em;
}

article p:first-of-type {
  font-size: 1.2em;
  font-weight: bold;
  color: #333;
}

article p:first-of-type::first-letter {
  font-size: 3em;
  float: left;
  line-height: 1;
  margin-right: 0.1em;
}

article p:last-of-type {
  text-align: center;
  font-style: italic;
  color: #6c757d;
}

4. 导航菜单

.nav {
  display: flex;
  list-style: none;
  padding: 0;
  margin: 0;
}

.nav li {
  position: relative;
}

.nav li:first-child a {
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
}

.nav li:last-child a {
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
}

.nav li:not(:last-child)::after {
  content: '';
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 60%;
  background: rgba(255,255,255,0.3);
}

5. 图片画廊

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 15px;
}

.gallery img {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 8px;
  transition: transform 0.3s ease;
}

.gallery img:nth-child(3n+1):hover {
  transform: scale(1.05) rotate(2deg);
}

.gallery img:nth-child(3n+2):hover {
  transform: scale(1.05) rotate(-2deg);
}

.gallery img:nth-child(3n):hover {
  transform: scale(1.05);
}

性能和最佳实践

1. 避免过度复杂的选择器

/* 不推荐 */
div > ul > li:nth-child(2n+1) > a {
  /* 样式 */
}

/* 推荐 */
.list-item:nth-child(odd) {
  /* 样式 */
}

2. 使用类名替代复杂选择器

/* 推荐 */
.highlight-item {
  background: #fff3cd;
}

/* 不推荐 */
li:nth-child(3n+1):not(.special) {
  background: #fff3cd;
}

3. 合理使用结构伪类

/* 推荐 - 简单规律 */
table tr:nth-child(even) {
  background: #f8f9fa;
}

/* 不推荐 - 过于复杂 */
li:nth-child(7n+3):nth-of-type(odd) {
  /* 样式 */
}

总结

CSS3 的结构伪类选择器提供了强大的基于文档结构的选择能力:

基础结构伪类:

  • :first-child - 第一个子元素
  • :last-child - 最后一个子元素
  • :only-child - 唯一的子元素
  • :empty - 空元素

高级结构伪类:

  • :nth-child(n) - 第 n 个子元素
  • :nth-last-child(n) - 倒数第 n 个子元素
  • :nth-of-type(n) - 同类型第 n 个元素
  • :nth-last-of-type(n) - 同类型倒数第 n 个元素
  • :first-of-type - 同类型第一个元素
  • :last-of-type - 同类型最后一个元素
  • :only-of-type - 同类型唯一元素

特殊伪类:

  • :root - 文档根元素

实际应用场景:

  • 创建斑马纹表格
  • 实现交替布局
  • 文章排版美化
  • 导航菜单样式
  • 图片画廊布局

最佳实践:

  • 合理使用结构伪类,避免过度复杂
  • 保持选择器的可读性和可维护性
  • 注意性能影响,避免嵌套过深
  • 结合类名使用,提高选择器效率

掌握这些结构伪类选择器,能够让我们更灵活地控制元素样式,创建更加精美的网页界面,同时保持 HTML 代码的简洁性。