序号选择器
概述
序号选择器是指基于元素在父元素中的位置顺序来选择元素的选择器。主要包括 :nth-child()、:nth-last-child()、:first-child、:last-child 等选择器。
基本序号选择器
1. :first-child - 第一个子元素
选择父元素的第一个子元素。
/* 选择第一个列表项 */
li:first-child {
color: red;
font-weight: bold;
}
/* 选择第一个段落 */
p:first-child {
text-transform: uppercase;
}<ul>
<li>第一个(红色粗体)</li>
<li>第二个</li>
<li>第三个</li>
</ul>
<div>
<p>第一个段落(大写)</p>
<p>第二个段落</p>
</div>2. :last-child - 最后一个子元素
选择父元素的最后一个子元素。
/* 选择最后一个列表项 */
li:last-child {
color: blue;
border-bottom: none;
}
/* 选择最后一个段落 */
p:last-child {
margin-bottom: 0;
}3. :only-child - 唯一的子元素
选择父元素中唯一的子元素。
/* 选择只有一个子元素的容器 */
.container:only-child {
text-align: center;
}
/* 选择只有一个子元素的列表项 */
li:only-child {
list-style: none;
}<div>
<p>这个元素是唯一的,会被选中</p>
</div>
<div>
<p>第一个</p>
<p>第二个(不唯一,不选中)</p>
</div>4. :nth-child(n) - 第 n 个子元素
选择父元素的第 n 个子元素。
/* 第2个子元素 */
li:nth-child(2) {
background-color: yellow;
}
/* 第1、3、5个元素(奇数) */
li:nth-child(odd) {
background-color: #f9f9f9;
}
/* 第2、4、6个元素(偶数) */
li:nth-child(even) {
background-color: #f0f0f0;
}
/* 每3个元素中的第1个 */
li:nth-child(3n+1) {
color: red;
}公式解释:
n: 从 0 开始的整数(0, 1, 2, 3, ...)an + b: 计算 n 的值
常用公式:
| 公式 | 说明 | 示例 |
|---|---|---|
2n | 偶数 | 2, 4, 6, 8... |
2n+1 | 奇数 | 1, 3, 5, 7... |
3n | 3的倍数 | 3, 6, 9, 12... |
3n+1 | 每3个中的第1个 | 1, 4, 7, 10... |
-n+3 | 前3个 | 1, 2, 3 |
n+4 | 从第4个开始 | 4, 5, 6, 7... |
5. :nth-last-child(n) - 倒数第 n 个子元素
从后往前数的第 n 个子元素。
/* 倒数第2个元素 */
li:nth-last-child(2) {
color: orange;
}
/* 倒数奇数位置 */
li:nth-last-child(odd) {
background-color: #f9f9f9;
}6. :first-of-type - 同类型的第一个子元素
选择父元素中该类型的第一个子元素。
/* 第一个段落 */
p:first-of-type {
font-size: 1.2em;
font-weight: bold;
}
/* 第一个标题 */
h3:first-of-type {
color: #3498db;
}<div>
<h2>标题1</h2>
<p>段落1(第一个p,被选中)</p>
<p>段落2</p>
<h3>标题2(第一个h3,被选中)</h3>
<h3>标题3</h3>
</div>7. :last-of-type - 同类型的最后一个子元素
选择父元素中该类型的最后一个子元素。
/* 最后一个段落 */
p:last-of-type {
margin-bottom: 0;
}
/* 最后一个链接 */
a:last-of-type {
color: #3498db;
}8. :nth-of-type(n) - 同类型的第 n 个子元素
选择父元素中该类型的第 n 个子元素。
/* 第2个段落 */
p:nth-of-type(2) {
color: red;
}
/* 奇数位置的段落 */
p:nth-of-type(odd) {
background-color: #f9f9f9;
}<div>
<h2>标题</h2>
<p>第1个段落</p>
<p>第2个段落(红色)</p>
<h3>标题2</h3>
<p>第3个段落</p>
</div>9. :nth-last-of-type(n) - 同类型的倒数第 n 个子元素
选择父元素中该类型的倒数第 n 个子元素。
/* 倒数第1个段落 */
p:nth-last-of-type(1) {
color: blue;
}
/* 等同于 */
p:last-of-type {
color: blue;
}10. :only-of-type - 唯一同类型子元素
选择父元素中该类型唯一的子元素。
/* 唯一的段落 */
p:only-of-type {
font-size: 1.5em;
text-align: center;
}
/* 唯一的标题 */
h3:only-of-type {
color: #3498db;
}<div>
<h3>唯一标题(被选中)</h3>
<p>段落1</p>
<p>段落2(不唯一)</p>
</div>权重计算
序号伪类选择器的权重为 10:
:first-child {
/* 权重 = 10 */
}
li:first-child {
/* 权重 = 1 + 10 = 11 */
}
.box:nth-child(2) {
/* 权重 = 10 + 10 = 20 */
}
.container .item:nth-child(3) {
/* 权重 = 10 + 10 + 10 = 30 */
}常见应用场景
1. 列表样式
/* 第一个列表项 */
li:first-child {
border-top: none;
margin-top: 0;
}
/* 最后一个列表项 */
li:last-child {
border-bottom: none;
margin-bottom: 0;
}
/* 除第一个外的所有列表项 */
li:not(:first-child) {
border-top: 1px solid #eee;
}
/* 奇偶条纹 */
li:nth-child(even) {
background-color: #f9f9f9;
}
/* 每3个一组 */
li:nth-child(3n) {
border-bottom: 2px solid #3498db;
}2. 表格样式
/* 表头 */
th {
background-color: #3498db;
color: white;
}
/* 斑马纹 */
tr:nth-child(even) {
background-color: #f9f9f9;
}
/* 悬停效果 */
tr:hover {
background-color: #e8f4fd;
}
/* 第一行 */
tr:first-child {
border-top: 2px solid #2980b9;
}
/* 最后一行 */
tr:last-child {
border-bottom: 2px solid #2980b9;
}<table>
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<tr>
<td>张三</td>
<td>25</td>
</tr>
<tr>
<td>李四</td>
<td>30</td>
</tr>
</table>3. 卡片布局
/* 第一个卡片 */
.card:first-child {
margin-top: 0;
}
/* 最后一个卡片 */
.card:last-child {
margin-bottom: 0;
}
/* 每3个一组 */
.card:nth-child(3n) {
margin-right: 0;
}
/* 悬停效果 */
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}4. 导航菜单
/* 第一个菜单项 */
.nav-item:first-child {
padding-left: 0;
}
/* 最后一个菜单项 */
.nav-item:last-child {
padding-right: 0;
}
/* 除第一个外的所有菜单项 */
.nav-item:not(:first-child) {
border-left: 1px solid #ddd;
}
/* 当前项 */
.nav-item.current {
background-color: #3498db;
color: white;
}5. 图片画廊
/* 图片容器 */
.gallery-item {
width: calc(33.333% - 20px);
margin-right: 20px;
margin-bottom: 20px;
}
/* 每3个一组,去除右边距 */
.gallery-item:nth-child(3n) {
margin-right: 0;
}
/* 最后3个去除下边距 */
.gallery-item:nth-last-child(-n+3) {
margin-bottom: 0;
}
/* 悬停效果 */
.gallery-item:hover {
transform: scale(1.05);
z-index: 1;
}6. 步骤指示器
/* 步骤项 */
.step {
display: inline-block;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 2px solid #ddd;
border-radius: 50%;
background: white;
}
/* 当前步骤 */
.step.current {
border-color: #3498db;
background: #3498db;
color: white;
}
/* 当前步骤之后的步骤 */
.step.current ~ .step {
border-color: #ddd;
opacity: 0.5;
}
/* 当前步骤之前的步骤 */
.step.current ~ .step::before {
content: "✓";
}7. 新闻列表
/* 新闻项 */
.news-item {
padding: 20px;
border-bottom: 1px solid #eee;
}
/* 第一个新闻项 */
.news-item:first-child {
border-top: 1px solid #eee;
}
/* 最后一个新闻项 */
.news-item:last-child {
border-bottom: none;
}
/* 前3个新闻项 */
.news-item:nth-child(-n+3) {
border-left: 4px solid #e74c3c;
}8. 评论系统
/* 评论项 */
.comment {
padding: 20px;
background: #f9f9f9;
margin-bottom: 20px;
border-radius: 10px;
}
/* 第一条评论 */
.comment:first-child {
margin-top: 0;
}
/* 最后一条评论 */
.comment:last-child {
margin-bottom: 0;
}
/* 嵌套评论 */
.comment .comment {
background: #fff;
margin-left: 40px;
margin-top: 20px;
}
/* 嵌套评论的第一条 */
.comment .comment:first-child {
margin-top: 10px;
}9. 标签页
/* 标签按钮 */
.tab-btn {
padding: 10px 20px;
background: #f5f5f5;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
/* 第一个标签 */
.tab-btn:first-child {
border-radius: 5px 0 0 5px;
}
/* 最后一个标签 */
.tab-btn:last-child {
border-radius: 0 5px 5px 0;
}
/* 激活的标签 */
.tab-btn.active {
background: #3498db;
color: white;
}
/* 标签内容 */
.tab-content {
display: none;
padding: 20px;
}
.tab-content.active {
display: block;
}10. 进度条
/* 进度条项 */
.progress-item {
display: inline-block;
width: 25%;
height: 8px;
background: #ddd;
border-radius: 4px;
}
/* 完成的步骤 */
.progress-item:nth-child(-n+3) {
background: #3498db;
}
/* 当前步骤 */
.progress-item:nth-child(3) {
background: #3498db;
box-shadow: 0 0 10px rgba(52, 152, 219, 0.5);
}
/* 未完成的步骤 */
.progress-item:nth-child(n+4) {
background: #ddd;
}实战案例
案例1: 产品网格
/* 产品网格 */
.product-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
/* 产品卡片 */
.product-card {
padding: 20px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
/* 前3个产品(热门) */
.product-card:nth-child(-n+3) {
border: 2px solid #e74c3c;
}
.product-card:nth-child(-n+3)::before {
content: "🔥 热门";
display: block;
color: #e74c3c;
font-weight: bold;
margin-bottom: 10px;
}
/* 悬停效果 */
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}案例2: 时间轴
/* 时间轴 */
.timeline {
position: relative;
padding-left: 40px;
}
/* 时间轴项 */
.timeline-item {
position: relative;
padding-bottom: 40px;
}
/* 时间点 */
.timeline-item::before {
content: "";
position: absolute;
left: -45px;
top: 0;
width: 20px;
height: 20px;
background: #3498db;
border-radius: 50%;
border: 4px solid white;
box-shadow: 0 0 0 2px #3498db;
}
/* 时间线 */
.timeline-item::after {
content: "";
position: absolute;
left: -35px;
top: 20px;
bottom: -20px;
width: 2px;
background: #ddd;
}
/* 偶数项时间线颜色 */
.timeline-item:nth-child(even)::before {
background: #27ae60;
box-shadow: 0 0 0 2px #27ae60;
}
/* 最后一个时间线 */
.timeline-item:last-child::after {
display: none;
}<div class="timeline">
<div class="timeline-item">
<h3>2024-01-01</h3>
<p>事件1</p>
</div>
<div class="timeline-item">
<h3>2024-02-01</h3>
<p>事件2</p>
</div>
<div class="timeline-item">
<h3>2024-03-01</h3>
<p>事件3</p>
</div>
</div>案例3: 图片幻灯片
/* 幻灯片容器 */
.slider {
position: relative;
overflow: hidden;
}
/* 幻灯片项 */
.slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 0.5s ease;
}
/* 第一张幻灯片(默认显示) */
.slide:nth-child(1) {
opacity: 1;
z-index: 1;
}
/* 幻灯片指示器 */
.indicator {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background: #ddd;
cursor: pointer;
}
/* 当前指示器 */
.indicator.active {
background: #3498db;
}案例4: 评分星星
/* 星星 */
.star {
display: inline-block;
width: 20px;
height: 20px;
color: #ddd;
font-size: 20px;
}
/* 前3颗星星 */
.star:nth-child(-n+3) {
color: #f39c12;
}
/* 悬停时点亮所有星星 */
.star-container:hover .star {
color: #f39c12;
}
/* 悬停时只点亮到当前星星 */
.star-container .star:hover ~ .star {
color: #ddd;
}
.star-container .star:hover {
color: #f39c12;
}<div class="star-container">
<span class="star">★</span>
<span class="star">★</span>
<span class="star">★</span>
<span class="star">★</span>
<span class="star">★</span>
</div>注意事项
- 索引从1开始: 序号选择器的索引从 1 开始,不是 0
- nth-child 公式:
an + b中 n 从 0 开始 - 类型无关:
:nth-child不考虑元素类型 - 类型相关:
:nth-of-type只考虑特定类型 - 性能考虑: 复杂的序号选择器可能影响性能
- 浏览器兼容: 现代浏览器都支持
最佳实践
- 语义化: 使用序号选择器实现视觉样式,不要用于语义
- 性能优化: 避免过于复杂的 nth-child 表达式
- 代码可读: 复杂选择器添加注释说明
- 组合使用: 与其他选择器配合使用
- 渐进增强: 为不支持的浏览器提供回退
- 测试兼容: 测试浏览器兼容性
总结
序号选择器是 CSS 中非常实用的选择器,能够基于元素的位置进行精确选择。掌握各种序号选择器的使用方法,可以帮助我们创建更丰富、更灵活的布局效果。在实际开发中,要合理使用序号选择器,确保代码的可维护性和性能。